编写高质量Python代码的59个有效方法 第6章 内置模块 第42条:用functools.wraps装饰wrapper装饰器

调试递归函数时我们常需要打印出每一步的参数及返回值,这时写个装饰器十分高效:

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)
>>>
.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对其做一些处理

你可能感兴趣的:(编写高质量Python代码的59个有效方法 第6章 内置模块 第42条:用functools.wraps装饰wrapper装饰器)