Python装饰器 *args 和 **kwargs

8

我刚开始学习编程,一直在尽力吸收尽可能多的知识。我不太理解你们发布的很多技术解释,所以请尽量使用简单易懂的英语。我了解如何使用装饰器函数,但我的问题是跟随代码逻辑 - 具体来说,为什么我们必须添加*args和** kwargs。是否正确地陈述:无论我们将什么传递给接受带有参数函数的装饰器函数,在装饰器中嵌套了的包装器函数总是会传递相同的参数,因为它嵌套在装饰器中?这就是我不明白的地方。我不理解原始函数中的参数如何被传递。


提供一个简单的例子会有所帮助,以确切地说明你在谈论什么(请参阅帮助中的“如何创建最小、完整和可验证的示例”)。在这种情况下,不是因为你谈论的内容不明显,而是因为使用你自己的例子来编写答案会更容易让你理解。 - abarnert
它们通过*args和**kwargs传递!或者你可以使用常规参数,但是装饰器只能用于匹配这些参数的函数。但是,如果没有像前面评论所建议的示例,这可能并没有太大帮助。 - avigil
1个回答

10
让我们来看一个简单的例子:
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的一组函数,并使用一个特定参数作为缓存键的装饰器,可以使用*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

但是通用的装饰器比特定的装饰器更多。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接