了解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 |