如何扩展图书馆的装饰器?

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 糖就可以这样处理。

以上是关于如何扩展图书馆的装饰器?的主要内容,如果未能解决你的问题,请参考以下文章

装饰器模式

类装饰器上的打字稿文档-返回“类扩展构造函数”的函数

图书管理系统(无中间件,用装饰器的)-----未基于FORM组件

装饰器模式与继承的例子

python装饰器

如何在 TypeScript 中使用装饰器