Python decorator 装饰器的 wrapper 问题

问题:

def log(func):
    def wrapper(*args, **kwargs):
        print('before call %s' % func.__name__)
        func(*args, **kwargs)
        print('after call %s' % func.__name__)

    return wrapper

@log
def test_func(a, b):
    print('%d + %d = %d' % (a, b, a + b))

使用 @log 的 decorator 后,以下的打印会跟预期的不一致,并不是预期的 test_func,而变成了 wrapper

>>> print('name: %s' % (test_func.__name__))

name: wrapper

原因:

之所以会这样,是因为在使用 decorator 后,test_func 变成了 log(test_func) 的返回,即 wrapper 函数。

解决:

标准库提供了 functools.wraps 这样的 decorator,可以这样使用来装饰上述 wrapper 函数:

 def log(func):
+    @functools.wraps(func)
     def wrapper(*args, **kwargs):
         print('before call %s' % func.__name__)
         func(*args, **kwargs)
         print('after call %s' % func.__name__)

     return wrapper

 @log
 def test_func(a, b):
     print('%d + %d = %d' % (a, b, a + b))
>>> print('name: %s' % (test_func.__name__))

name: test_func

这样就跟预期的结果一致了。

Read More: