让我们举一个简单的例子:
def tracing(func):
@functools.wraps
def wrapper(*args, **kwargs):
logging.debug(f'Calling {func.__name__}')
try:
return func(*args, **kwargs)
finally:
logging.debug(f'Called {func.__name__}')
return wrapper
@tracing
def spam():
print('spam')
@tracing
def add3(n):
return n+3
你说得对,我们需要采取的理由*args, **kwargs
这样我们就可以通过同样的*args, **kwargs
到包装的函数。
这称为“转发”,或“完美转发”。这个想法是tracing
不必知道有关它所包装的函数的任何信息 - 它可以采用任何一组位置参数和关键字参数,并返回任何内容,并且包装器仍然可以工作。
对于某些装饰器来说,这是不合适的。例如,一个装饰器旨在缓存一组具有相同 API 的函数,使用一个特定参数作为缓存键,could use *args, **kwargs
然后通过列表和字典来查找特定参数,但明确地说,它更简单、更清晰:
def caching_spam(func):
cache = {}
@functool.wraps
def wrapper(eggs, beans, spam, cheese):
if spam not in cache:
cache[spam] = func(eggs, beans, spam, cheese)
return cache[spam]
return wrapper
但通用装饰器比特定装饰器要多得多。