装饰器工作原理
先用一个例子体会一下
def funA(fn): # 装饰器函数
print("--1--")
fn()
print("--2--")
print("******")
return "--3--"
def funB():
print("--funB--")
funB = funA(funB) ###
print(funB)
使用装饰器之后,代码就可以变成这样
def funA(fn): # 装饰器函数
print("--1--")
fn()
print("--2--")
print("******")
return "--3--"
@funA
## 等价于 funB = funA(funB)
def funB():
print("--funB--")
print(funB)
输出结果如下
--1--
--funB--
--2--
******
--3--
装饰器完成了以下功能:
- 将funB作为参数传给funA()函数
- 将funA函数执行完的返回值return反馈给funB
总结:
所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。
修饰的函数不再是原来的函数,而是被替换成一个新的东西(取决于装饰器的返回值),即如果装饰器函数的返回值为普通变量,那么被修饰的函数名就变成了变量名;同样,如果装饰器返回的是一个函数的名称,怎么被修饰的函数名依然表示一个函数。
函数名字和注释文档
def a_new_decorator(a_func):
def wrapTheFunction():
print("before executing a_func()")
a_func()
print("after executing a_func()")
print("************")
return wrapTheFunction
@a_new_decorator
# a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
def a_function_requiring_decoration():
print("I am the function")
a_function_requiring_decoration()
print(a_new_decorator.__name__) # a_new_decorator
print(a_function_requiring_decoration.__name__) # wrapTheFunction
a_function_requiring_decoration重写了
python提供一个简单函数functools.wraps修改
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func)
def wrapTheFunction():
print("before executing a_func()")
a_func()
print("after executing a_func()")
return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
print("I am the function")
print(a_function_requiring_decoration.__name__) # a_function_requiring_decoration
注意
@wraps接受一个函数进行装饰,并加入了复制函数名称、注释文档、参数列表等功能。可以让我们在装饰器里面访问在装饰之前的函数的属性。
带有多个参数
from functools import wraps
def decorator_name(f):
@wraps(f)
def decorated(*args, **kwargs):
if not can_run: # False
return "Function will not run"
return f(*args, **kwargs) # True
return decorated
@decorator_name
def func():
return("Function is running")
can_run = True
print(func())
# Output: Function is running
can_run = False
print(func())
# Output: Function will not run
日志中常用到装饰器
from functools import wraps
def logit(func):
@wraps(func)
def with_logging(*args, **kwargs):
print(func.__name__ + " was called")
return func(*args, **kwargs)
return with_logging
@logit
def addition_func(x):
"""Do some math."""
return x + x
result = addition_func(4)
# Output: addition_func was called