如何将装饰器中的变量传递给装饰函数中的函数参数?

Posted

技术标签:

【中文标题】如何将装饰器中的变量传递给装饰函数中的函数参数?【英文标题】:How can I pass a variable in a decorator to function's argument in a decorated function? 【发布时间】:2010-12-30 06:03:24 【问题描述】:

我正在学习 Python。希望有人指出我正确的方法。 这就是我想做的事情:

def decorate(function):
    def wrap_function(*args, **kwargs):
        str = 'Hello!'  # This is what I want
        return function(*args, **kwargs)
    return wrap_function

@decorate
def print_message():
    # I'd like to pass 'str' as mentioned above
    # to any functions' argument like below:
    print(str)  # 'str' is same as above

有什么想法吗?提前致谢。

【问题讨论】:

【参考方案1】:

您不能将其作为自己的名称传递,但可以将其添加到关键字中。

def decorate(function):
    def wrap_function(*args, **kwargs):
        kwargs['str'] = 'Hello!'
        return function(*args, **kwargs)
    return wrap_function

@decorate
def print_message(*args, **kwargs):
    print(kwargs['str'])

或者你可以命名它自己的参数:

def decorate(function):
    def wrap_function(*args, **kwargs):
        str = 'Hello!'
        return function(str, *args, **kwargs)
    return wrap_function

@decorate
def print_message(str, *args, **kwargs):
    print(str)

类方法:

def decorate(function):
    def wrap_function(*args, **kwargs):
        str = 'Hello!'
        args.insert(1, str)
        return function(*args, **kwargs)
    return wrap_function

class Printer:
    @decorate
    def print_message(self, str, *args, **kwargs):
        print(str)

【讨论】:

请注意,第一个解决方案也可以通过使用functools.partial() 来实现(但仅从 2.6 版本开始)。同一个模块还提供了wraps() 函数,它可以与装饰器一起使用来维护原始函数的名称和文档。 @RedGlyph:为什么只使用 2.6 版中的functools.partial()?除了 functools 模块是 pyhton 2.5 中的新模块之外,文档只字未提。 感谢 Tor Valamo。替代解决方案对我来说很清楚。但是如果装饰函数是一个实例方法呢?实例方法的参数应该类似于:def print_message(str, self, *args, **kwargs): 这是正确的吗?再次感谢。 是的,这是因为 args 列表包含“self”作为第一项。您可以使用 args.insert(1, str) 修复它,然后返回 function(*args, **kwargs) @Japboy:我不知道你是否注意到,但print_message 不需要额外的*args**kwargs 参数,所以不要声明,所以如果你不需要,你可以运行它。恕我直言,装饰器越强大,装饰功能越不知道它【参考方案2】:

如果您希望参数是“可选注入的”,只有在函数实际使用它的情况下,才使用如下内容:

import inspect

def decorate(func):
    def wrap_and_call(*args, **kwargs):
        if 'str' in inspect.getargspec(func).args:
            kwargs['str'] = 'Hello!'
        return func(*args, **kwargs)
    return wrap_and_call

@decorate
def func1(str):
    print "Works! - " + str

@decorate
def func2():
    print "Should work, also."

【讨论】:

请注意,不推荐使用 getargspec。对于 Python3,请使用 getfullargspec。 或者:inspect.signature(func).parameters 中的'str'

以上是关于如何将装饰器中的变量传递给装饰函数中的函数参数?的主要内容,如果未能解决你的问题,请参考以下文章

装饰器中的 Python Access 函数变量

将命令行参数传递给调用带有装饰器参数的装饰函数的函数

如何将实例变量传递给打字稿装饰器参数?

python_如何修改装饰器中参数?

装饰器中添加参数

装饰器中添加参数