将函数传递给装饰器

Posted

技术标签:

【中文标题】将函数传递给装饰器【英文标题】:Passing a function to a decorator 【发布时间】:2021-11-15 06:07:43 【问题描述】:

我有一个库证明以下代码:

class LibClass:
    def decorator_method(self, *args, **kwargs):
        # some code...
        pass

打算按如下方式使用:

k = LibClass()
method_args = (,) # something I create

@k.decorator_method(method_args)
def my_func():
    # Code that I want to run
  

具体来说,该库通过这些装饰器实现了一些类似回调的功能。当然,我无法控制该库,也没有任何替代功能。

重要的是,LibClass 的实例是装饰器的一部分,因此 my_func 被添加到该实例 k 的回调中。

但是,我在代码的其他地方实现了my_func,我想将功能与装饰分开。一种方法是像这样创建一个包装器:

k = LibClass()

@k.decorator_method(method_args)
def my_func_wrapper():
    # Actual call
    my_func()

这种方法按我想要的方式工作,但它的缺点是必须定义和调用并非绝对必要的包装函数。但是,我显然不能直接应用装饰器,因为

def my_func():
    # ...

@k.decorator_method(method_args)
my_func

不是有效的 Python 代码。同样,我可能会考虑以这种方式装饰闭包,例如

def my_func_producer(more_args):
    def my_func():
        # Do something with more_args

    return my_func

在哪里

more_args = (,)

@k.decorator_method(method_args)
my_func_producer(more_args)

也是无效的。有什么方法可以应用装饰器而无需定义额外的包装函数?

【问题讨论】:

这能回答你的问题吗? how to do a conditional decorator in python “我显然不能直接应用装饰器,”当然你可以。定义myfunc 后,只需执行myfunc = k.decorator_method(method_args)(myfunc)。这就是@ 语法糖首先要做的事情 装饰器语法只是一个捷径。如果my_func 已经定义,你可以简单地写my_func = k.decorator_method(method_args)(my_func)。如果你的装饰器实际上并没有创建一个新函数,只是用k注册它,你可以省略赋值。 顺便说一句,我相信你想要k.decorator_method(*method_args) 而不仅仅是k.decorator_method(method_args) 【参考方案1】:

而不是这个:

def my_func():
    # ...

@k.decorator_method(method_args)
my_func

这样做:

def my_func():
    # ...

my_func = k.decorator_method(method_args)(my_func)

这正是装饰器所做的,但只是为了一个小细节。装饰器的“@”语法在 2.3 版本中作为语法糖被引入:可调用的装饰器(放置在@ 之后)使用从下一行开始定义的函数作为其唯一参数来调用。

所以,如果我们只是用通常的调用语法调用同一个装饰器,将函数本身作为参数传递,效果是一样的。在这种情况下,我们必须将装饰对象重新绑定到函数名称,因此调用之前的 my_func = ...。 (@syntax 进行了隐式名称绑定,这就是我在第一段中提到的“次要细节”)

【讨论】:

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

(Python) 将 Playwright Page 对象传递给包装函数的函数装饰器

实现 python 装饰器以将函数传递给另一个函数

将默认参数传递给python中的装饰器

在 Python 中,如何获取带参数传递给装饰器的函数名称?

如何将非硬编码参数传递给 Python 装饰器?

将参数传递给要装饰的类方法的装饰器