将函数传递给装饰器
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 对象传递给包装函数的函数装饰器