了解Python装饰器
概念了解
装饰器是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
例如a()、b()等等函数都需要打印日志,为了减少“打印日志”部分代码的重复,就把这部分与函数功能本身无关的雷同代码抽离出来,并以装饰器的格式去重用它。
常见场景
插入日志、性能测试、事务处理、缓存、权限校验等等。
代码示例
如何理解Python装饰器?https://www.zhihu.com/question/26930016/answer/99243411
1 | def func_a(): |
func_a()、func_b()中都有打印日志的代码,如果之后还有函数func_c、func_d也需要打印日志,这样就造成大量打印日志的雷同代码。
为了减少重复写代码,我们可以这样做,重新定义一个函数print_log专门处理打印日志的功能,并且在func_a、func_b中使用它。
1 | def print_log(func): |
但是这样的话,我们每次都要将一个函数作为参数传递给print_log函数。而且这种方式已经破坏了原有的代码逻辑结构,之前执行业务逻辑时,执行运行func_a(),但是现在不得不改成print_log(func_a)。
- 那么有没有更好的方式的呢?
Python装饰器
1 | # 这是一个简单的装饰器 |
@符号是装饰器的语法糖,在定义函数的时候使用,避免再一次赋值操作。
1 | # 装饰器,应用 @ 语法糖写法 |
装饰器丢失原函数信息
元信息丢失
使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的docstring、__name__、参数列表,先看例子。
1 |
|
也就是说函数func_a被print_log所替代,即func_a的docstring,__name__等等信息都是with_logging函数的信息。
1 | func_a.__name__ = 'with_logging' |
解决办法
使用functools.wraps,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。
(wraps也是一个装饰器)
1 | from functools import wraps |