通常情况下,给一个对象添加新功能有三种方式:
一般情况下,优先使用组合,而不是继承。但是装饰器属于第四种,动态的改变对象从而扩展对象的功能。
一般装饰器的应用场景有打印日志,性能测试,事务处理,权限校验;
理解Python装饰器工作原理,首先需要理解闭包这一概念。闭包指的是一个函数嵌套一个函数,内部嵌套的函数调用外部函数的
变量,外部函数返回内嵌函数,这样的结构就是闭包。
装饰器就是闭包的一种应用,但是装饰器参数传递的是函数。
简单的闭包示例:
def add_num(x): def sum_num(y): return x+y return sum_num add_num5 = add_num(5) total_num = add_num5(100) print(total_num)
注解:
简单计算函数运行时间装饰器示例:
def times_use(func): def count_times(*args, **kwargs): start = time.time() result = func(*args, **kwargs) end = time.time() print(end-start) return result return count_times @times_use def test_decorator(): time.sleep(2) print("Test Decorator") test_decorator()
注解:
根据日志等级打印日志装饰器示例(带参数的装饰器):
def use_logging(level): def decorator(func): def wrapper(*args, **kwargs): if level == "warn": logging.warn("%s is running"% func.__name__) result = func(*args, **kwargs) print(result) return result return wrapper return decorator @use_logging("warn") def test_decorator(): print("Test Decorator") return "Success" test_decorator()
计算函数运行时间的类装饰器示例:
class logTime: def __init__(self, use_log=False): self._use_log = use_log def __call__(self, func): def _log(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) print(result) end_time = time.time() if self._use_log: print(end_time-start_time) return result return _log @logTime(True) def test_decorator(): time.sleep(2) print("Test Decorator") return "Success"
使用装饰器虽然能在保存原有代码逻辑的基础上扩展功能,但是原有函数中的元信息会丢失,比如__name__, __doc__,参数列表。针对这种情况
可以使用functools.wraps,wraps也是一个装饰器,但是会将原函数的元信息拷贝到装饰器函数中。
具体使用方法:
from functools import wraps def use_logging(level): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): if level == "warn": logging.warn("%s is running"% func.__name__) result = func(*args, **kwargs) print(result) return result return wrapper return decorator @use_logging("warn") def test_decorator(): """" Test Decorator DocString"""" time.sleep(2) print("Test Decorator") return "Success" print(test_decorator.__name__) print(test_decorator.__doc__)
注解:
在日常业务中经常会使用多个装饰器,比如权限验证,登录验证,日志记录,性能检测等等使用场景。所以在使用多个装饰器
时,就会涉及到装饰器执行顺序的问题。先说结论,关于装饰器执行顺序,可以分为两个阶段:(被装饰函数)定义阶段、(被装饰函数)执行阶段。
多装饰器示例:
def decorator_a(func): print("Get in Decorator_a") def inner_a(*args, **kwargs): print("Get in Inner_a") result = func(*args, **kwargs) return result return inner_a def decorator_b(func): print("Get in Decorator_b") def inner_b(*args, **kwargs): print("Get in Inner_b") result = func(*args, **kwargs) return result return inner_b @decorator_b @decorator_a def test_decorator(): """test decorator DocString""" print("Test Decorator") return "Success"
运行结果:
Get in Decorator_a Get in Decorator_b Get in Inner_b Get in Inner_a Test Decorator
代码注解:
https://www.zhihu.com/question/26930016
https://segmentfault.com/a/1190000007837364
https://blog.csdn.net/u013411246/article/details/80571462