如何对一个可调用对象应用多个装饰器?

6 投票
2 回答
1783 浏览
提问于 2025-04-16 06:44

假设你有一堆装饰器方法,你想把它们应用到一个可以调用的东西上,比如一个函数。

举个例子,因为:

@foo
@bar
def baz():
    pass

...和下面这个是一样的:

def baz():
    pass
baz = foo(bar(baz)))

...所以人们会想,如果有一个装饰器的列表(比如[foo, bar]),那么就可以动态地把它们应用到baz这个函数上。

2 个回答

2

这是一个经典的例子:

def compose(f, g):
    def composed(*a, **k):
        return g(f(*a, **k))
    return composed

@compose(foo, compose(bar, baz))
def blam():
    pass
14

又来了一个装饰器!

def yad(decorators):
    def decorator(f):
        for d in reversed(decorators):
            f = d(f)
        return f
    return decorator

示例用法

 list_of_decorators = [foo, bar]

@yad(list_of_decorators)
def foo():
    print 'foo'

如果没有装饰器的语法,它看起来会是这样的

 func = yad(list_of_decorators)(func)

如果你想把同一个列表应用到多个函数上,可以这样做:

 dec = yad(list_of_decorators)

 func1 = dec(func1)

 @dec
 def func2():
     pass

正如递归在评论中提到的,你可以定义一个叫 yad(我相信还有更好的名字)来接受 *decorators,而不是 decorators。这样的话,如果你在创建列表的时候不需要用括号就可以了。我的示范方式更适合在其他地方创建列表的情况。

撰写回答