我对编码很陌生,而且我一直试图尽可能地吸收。我不太了解你们发布的很多技术解释,所以请尽量用简单的英语。我得到了装饰器函数如何工作的机制,但我的问题是遵循代码逻辑 - 特别是为什么我们必须添加* args和** kwargs。声明无论我们传入装饰器函数接受带有参数的函数,它都会正确地将相同的参数传递给包装函数,因为它嵌套在装饰器中吗?这就是我在这里失踪的地方。我不明白原始函数的参数是如何传入的。
答案 0 :(得分:2)
我们举一个简单的例子:
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
不必知道它包装的功能 - 它可以采用任何一组位置和关键字参数,并返回任何内容,并且包装器仍然可以工作。 / p>
对于一些装饰者来说,这是不合适的。例如,设计用于缓存一组所有具有相同API的函数的装饰器,使用一个特定参数作为缓存键,可以使用*args, **kwargs
然后munge通过列表和字典找到特定的参数,但它更简单,更清晰,更明确:
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
但是除了特定的装饰器之外,还有更多的通用装饰器。