调试递归函数时我们常需要打印出每一步的参数及返回值,这时写个装饰器十分高效:
def trace(func):
def wrapper(*args, **kw):
result = func(*args, **kw)
print(f"{func.__name__}({args}, {kw}) --> {result}")
return result
return wrapper
@trace
def fibonacci(n):
if n in (0, ):
return 0
return fibonacci(n-1) + fibonacci(n-2)
fibonacci(4)
>>>
fibonacci((1,), {}) --> 0
fibonacci((0,), {}) --> 0
fibonacci((2,), {}) --> 0
fibonacci((1,), {}) --> 0
fibonacci((3,), {}) --> 0
这种写法的缺陷在于变量fibonacci变成了wrapper:
help(fibonacci)
>>>
Help on function wrapper in module __main__:
wrapper(**args, **kwargs)
print(fibonacci)
>>>
<function trace.<locals>.wrapper at 0x0000012B1C774598>
为了维护函数的接口,修饰后的函数,必须保留原函数的某些标准python属性,例如,__name__,__module__。因此我们需要wraps来装饰wrapper:
from functools import wraps
def trace(func):
@wraps
def wrapper(*args, **kw):
result = func(*args, **kw)
print(f"{func.__name__}({args}, {kw}) --> {result}")
return result
return wrapper
要点
- 内置的functools模块提供了名为wraps的装饰器,开发者定义自己的装饰器时,应用wraps对其做一些处理