流畅的python--装饰器

装饰器:以某种方式增强函数。
两大特性:1、可以将被装饰的函数替换成其他函数。
2、在加载模块时立即执行。

案例1
def make_avarage():
count=0
total=0
def averager(new_value):
count+=1
total+=new_value
return total/count
return averager
这里会报错,averager里面是一个新的 count、total变量


案例2
使用nolocal作用:将变量标记为自由变量,
def make_avarage():
count=0
total=0
def averager(new_value):
nonlocal count,total
count+=1
total+=new_value
return total/count
return averager


案例3

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun May  3 23:27:22 2020

@author: root
"""


     promos=[]
     def promotion(promo_func):
         promo.append(promo_func)
         return promo_func

     @promotion
     def  FidelityPromo(order):
          return order.total()*0.05 if order.customer.fidelity>=1000 else 0

     @promotion
     def BulkItemPromo(order):
         discount = 0
         for item in order.cart:
             if item.quantity>=20:
                discount+=item.total()*0.1
         return discount

    @promotion 
    def LargeOrderPromo(order):
        discount_items = {item.product for item in order.cart}
        if len(discount_items)>=10:
           return order.total()*0.07
        return 0
    
    def best_promo(order):
        return max(promo(order) for promo in promos)

二、@property:方法伪装属性,方法返回值及属性值,被装饰方法不能有参数,必须实例化后调用,类不能调用
#@ property
#将一个方法伪装成属性,被修饰的特性方法,内部可以实现处理逻辑,但对外提供统一的调用方式,实现一个实例属性的

getter
setter
d elete
三种方法的内部逻辑,具体含义看示
class Data:

    def __init__(self):
       self.number = 123

    @property
    def operation(self):
       return self.number

@operation
.getter
def operation(self):
return self.number
@operation.setter
def operation(self, number): self.number = number @operation.deleter def operation(self): del self.number

案例1----普通写法
class Student(object):
def get_score(self):
return self._score

def set_score(self,value):
if not isinstance(value,int):
raise ValueError('pppppp')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value


Python内置的@property装饰器就是负责把一个方法变成属性调用
案例1----装饰器写法



class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('pppppp')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value
s=Student()
s.score=60
s.score=9999
print (s.score)

三、类装饰器:类装饰器使用地方较少,核心是通过复写类的回调方法call.

装饰器应用场景:

1、引入日志
2、函数执行时间统计
3、执行函数前预备处理
执行函数后清理功能
权限校验等场景
缓存

方法:__call__
__call__ 方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable
class Add:

def __init__(self, fn):
print("初始化")
self.num = 44
self.fn = fn

def __call__(self, *args, **kwargs):
print("类装饰器开始工作")
return self.fn(self.num)

@Add
def test(n):
return 4+n

if __name__ == '__main__':
num = test()
print(num)



结果:
初始化
<function test at 0x7f95f883bc20>
类装饰器开始工作
44
48
 
 

 案例1

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May  4 22:11:44 2020

@author: root
简单注册表
"""


funcs = []
def register(func):
    funcs.append(func)
    return func
    
    
@register
def a():
    return 3
    
@register
def b():
    return 5

def c():
    return 8   

# 访问结果
result = [func() for func in funcs]
print(funcs)
print(result)

# [<function a at 0x7f95f8837050>, <function b at 0x7f95f8837290>]
# [3, 5]

案例2

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May  4 22:14:37 2020

@author: root

注册表隔离(使用类的不同实例)
"""


class Registry(object):
    def __init__(self):
        self._funcs=[]

    def register(self,func):
        self._funcs.append(func)

    def run_all(self):
        return [func() for func in self._funcs]

r1=Registry()
r2=Registry()


@r1.register
def a():
    return 3


@r2.register
def b():
    return 5




案例3

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May  4 22:30:41 2020

@author: root

用户验证
"""


from functools import wraps

class User(object):
    def __init__(self, username, email):
        self.username = username
        self.email = email
        
class AnonymousUser(object):
    def __init__(self):
        self.username = self.email = None
        
    def __nonzero__(self):  # 将对象转换为bool类型时调用
        return False
        
    
def requires_user(func):
    @wraps(func)
    def inner(user, *args, **kwargs):  # 由于第一个参数无法支持self, 该装饰器不支持装饰类
        if user and isinstance(user, User):
            return func(user, *args, **kwargs)
        else:
            raise ValueError("非合法用户")
    return inner


a=User('teddy', '120@163.com')
print (a)

案例3

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May  4 22:36:47 2020

@author: root

异常捕获
"""


import json
from functools import wraps

class Error1(Exception):
    def __init__(self, msg):
        self.msg = msg
    def __str__(self):
        return self.msg
        

def json_output(func):
    @wraps(func)
    def inner(*args, **kwargs):
        try:
            result = func(*args, **kwargs)
        except Error1 as ex:
            result = {"status": "error", "msg": str(ex)}
        return json.dumps(result)
    return inner

# 使用方法
@json_output
def error():
    raise Error1("该条异常会被捕获并按JSON格式输出")

案例3

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon May  4 22:40:47 2020

@author: root

日志管理
""

import time
import logging
from functools import wraps

def logged(func):
    @wraps(func)
    def inner(*args, **kwargs):  # *args可以装饰函数也可以装饰类
        start = time.time()
        result = func(*args, **kwargs)
        exec_time = time.time() - start
        logger = logging.getLoger("func.logged")
        logger.warning("{} 调用时间:{:.2} 执行时间:{:.2}s 结果:{}".format(func.__name__, start, exec_time, result))
资源清理#import pymysql

class DBConnection(object):
    def __init__(self, *args, **kwargs):
        self.args,self.kwargs = args, kwargs
        
    def __enter__(self):
        self.conn = pymysql.connect(*args, **kwargs)
        return self.conn.cursor()
        
    def __exit__(self, exc_type, exc_instance, trackback):
        self.conn.close()
 案例来源:https://www.cnblogs.com/superhin/p/11454823.html
原文地址:https://www.cnblogs.com/1314520xh/p/12824712.html