为什么装饰器需要 @wraps

@wraps 保留原始函数的属性,否则装饰后的函数的属性将被 **包装函数** 替换。例如

不使用 @wraps

>>> def decorator(func):
...     def wrapper(*args, **kwargs):
...         print('wrap function')
...         return func(*args, **kwargs)
...     return wrapper
...
>>> @decorator
... def example(*a, **kw):
...     pass
...
>>> example.__name__  # attr of function lose
'wrapper'

使用 @wraps

>>> from functools import wraps
>>> def decorator(func):
...     @wraps(func)
...     def wrapper(*args, **kwargs):
...         print('wrap function')
...         return func(*args, **kwargs)
...     return wrapper
...
>>> @decorator
... def example(*a, **kw):
...     pass
...
>>> example.__name__  # attr of function preserve
'example'