如何扩展图书馆的装饰器?
Posted
技术标签:
【中文标题】如何扩展图书馆的装饰器?【英文标题】:How can I extend a library's decorator? 【发布时间】:2016-03-30 08:04:50 【问题描述】:我想扩展一个库的装饰器。我知道我可以同时调用两个装饰器:
@my_decorator
@lib_decorator
def func():
pass
但我想避免每次都将@lib_decorator
传递给每个函数。我希望我的装饰器自动用lib_decorator
装饰func()
。我怎样才能做到这一点?可以嵌套吗?
【问题讨论】:
【参考方案1】:您可以将 lib 的装饰器合并到您的装饰器中。对于简单、无参数的装饰器,它相当简单:
def my_decorator():
@lib_decorator # <--- Just include the lib's decorator here
def inner:
func(*args, **kwargs)
return inner
对于有参数的装饰器来说,这有点棘手。请记住,您的装饰器正在用最里面的函数替换装饰函数。所以这就是你需要装饰的那个。因此,如果您使用 args 调用您的装饰器,例如
@my_decorator(arg)
def func():
pass
然后用lib装饰器装饰内部函数:
def my_decorator(arg):
def wrapper(func):
@lib_decorator # <--- Just include the lib's decorator here
def inner(*args, **kwargs):
func(*args, **kwargs)
return inner
return wrapper
或者,使用装饰器函数的class
形式:
class my_decorator():
def __init__(self, arg):
pass
def __call__(self, func):
@lib_decorator # <--- Just include the lib's decorator here
def inner(*args, **kwargs):
func(*args, **kwargs)
return inner
【讨论】:
你的两个示例装饰器都有一个额外的层,只有当你想支持将参数传递给装饰器时才需要它(例如@my_decorator("foo")
)。对于像问题中没有被用户调用的装饰器(只是命名,例如@my_decorator
),您不需要该层。
谢谢,@Blckknght。我相信我的示例装饰器适用于 function 需要参数,而不是 decorator (例如,func("foo")
,不是吗?无论哪种方式,我都承认它不需要问题中的示例,我只是想提供最完整的解决方案,以防它与其他任何人相关。
是的,它们支持带参数的函数,但我说的是@my_decorator
无法应用它们。由于额外的层,您需要@my_decorator()
(调用装饰器工厂,它返回装饰器,@
语法调用函数,返回内部包装的函数)。如果你在你的函数版本中去掉wrapper
,它就可以在没有括号的情况下工作。类版本有点棘手,因为并非所有装饰器都能很好地处理方法。你可能希望__call__
做return lib_decorator(self.func)(*args, **kwargs)
。
@Blckknght,谢谢。这有助于让我更清楚地了解情况。在我之前的所有阅读中,我都没有发现 @my_decorator
和 @my_decorator()
之间的区别。
arg
如何传递给lib_decorator
?【参考方案2】:
您可以轻松改造您的装饰:
@my_decorator
@lib_decorator
def func():
pass
为了这个更简单的装饰,使用函数组合:
my_composed_decorator = lambda func: my_decorator(lib_decorator(func))
@my_composed_decorator
def func():
pass
【讨论】:
我喜欢你展示的函数组合方法,因为它回忆起装饰器确实是函数返回函数,无需使用@something
糖就可以这样处理。以上是关于如何扩展图书馆的装饰器?的主要内容,如果未能解决你的问题,请参考以下文章