【问题标题】:python decorators *args and ** kwargspython 装饰器 *args 和 ** kwargs
【发布时间】:2018-08-28 19:18:20
【问题描述】:

我是编码新手,我一直在尝试尽可能多地吸收。你们发的很多技术解释我都看不懂,所以请尽量保持简单的英文。我了解了装饰器函数如何工作的机制,但我的问题是遵循代码逻辑——特别是为什么我们必须添加 *args 和 ** kwargs。声明我们传递给装饰器函数的任何内容是否正确,该函数接受一个有参数的函数,总是将相同的参数传递给包装函数,因为它嵌套在装饰器中?这就是我在这里所缺少的。我不明白原始函数的参数是如何传入的。

【问题讨论】:

  • 这将有助于提供一个简单的例子来说明您正在谈论的内容(请参阅帮助中的How to create a Minimal, Complete, and Verifiable example)。在这种情况下,并不是因为您在说什么并不明显,而是因为使用您自己的示例编写一个您可以理解的答案会更容易。
  • 它们是通过 *args 和 **kwargs 传入的!或者你可以使用常规参数,真的,但是装饰器只适用于匹配这些参数的函数。但是,正如先前的评论所暗示的那样,如果没有一个例子,这可能无济于事。

标签: python decorator


【解决方案1】:

我们举个简单的例子:

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,然后通过列表和 dict 搜索找到那个特定的参数,但它更简单,更清晰,更明确:

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

但通用装饰器比特定装饰器多得多。

【讨论】:

    猜你喜欢
    • 2013-09-25
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    • 2017-01-28
    • 1970-01-01
    • 2016-04-20
    • 2020-07-15
    • 2014-04-26
    相关资源
    最近更新 更多