为什么使用装饰工厂工厂函数出现语法错误?

时间:2017-06-04 19:34:49

标签: python syntax-error python-decorators

说我有一个装饰工厂工厂。它是无用的,只是累积参数,并添加到结果中,但仅作为一个例子:

def decorator_factory_factory(a):
    def decorator_factory(b):
        def decorator(f):
            def decorated(*args, **kwargs):
                return f(*args, **kwargs) + a + b
            return decorated
        return decorator
    return decorator_factory

我试着像这样使用它:

@decorator_factory_factory(3)(1)
def should_return_5():
    return 1

我得到一个SyntaxError。当然它应该允许任意Python表达式作为装饰器?

我也尝试过:

@(decorator_factory_factory(3)(1))
def should_not_be_touched():
    return 1

但这是另一个SyntaxError。

我做错了吗?我找到的唯一方法是:

_decorator_factory = decorator_factory_factory(3)
@_decorator_factory(1)
def should_not_be_touched():
    return 1
del _decorator_factory

但这需要另外一个需要删除的变量

2 个答案:

答案 0 :(得分:1)

修饰器语法is restricted。您不允许使用任意表达式。允许您使用.运算符,最后最多只能使用一个调用(),因此

@decorator_factory_factory(3)(1)
def should_return_5():
    return 1

是语法错误,因为它的调用(3)不在结尾。

实际上,这不是限制,因为装饰器只是函数声明后的赋值糖。您可以不受限制地自己做

def should_return_5():
    return 1
should_return_5 = decorator_factory_factory(3)(1)(should_return_5)

不会创建需要删除的其他变量。

此外,单个函数调用就足以通过一个简单的标识函数潜入任意表达式。

def identity(x):
    return x

@identity(decorator_factory_factory(3)(1))
def should_return_5():
    return 1

使用identity的短名称(不是id,这是内置的),这与您想要的@(decorator_factory_factory(3)(1))语法非常接近。

答案 1 :(得分:0)

该函数是在错误的包装器上发送的,从未调用

def decorator_factory_factory(): 
    def decorator_factory(f):
        def decorator():
            return f()
        return decorator
    return decorator_factory

@decorator_factory_factory()
def should_not_be_touched():
    return 1