带有装饰器的意外SyntaxError

时间:2015-03-11 19:32:44

标签: python

这里的目标是将全局函数称为装饰器。

#coding: utf-8
def Test(method_to_decorate):
    print 'Decorator'
    def wrapper(self):
        return method_to_decorate(self)
    return wrapper


class Smth(object):
    def Test(self):
        print 'NOT a decorator!'

    a=globals()['Test']

    #@globals()['Test'] --> SyntaxError
    @a # works fine
    def Fun(self):
        print "Smth.Fun()"

l = Smth()
l.Fun()

@globals()['Test']给出SyntaxError时,使用未注释的方法可以正常工作。 为什么?我非常确定Testglobals() 存在

@之后的事物必须是一个接受另一个函数作为其参数之一的函数,我是对的吗? globals()['Test']就是这样一个功能,不是吗?然后,在我看来,@globals()['Test']必须是正确的(逻辑上正确)。

修改

这可以按预期工作:

def Ex(*args):
    print 'Ex({})'.format(args) 
globals()['Ex']('hello') # just calling a function

使用装饰器时,会调用一个函数。我们可以像上面那样调用函数,但是不能像这样使用装饰器。 也许这是某种Python错误或逻辑错误组织?

2 个答案:

答案 0 :(得分:6)

这是一个SyntaxError,因为Python的语法明确不允许这样做; @右侧的标记不是表达式。 1相反,有效的语法是:

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE

(括在方括号([ ])中的短语表示零次或一次出现(换句话说,随附的短语是可选的)。)2

根据上述内容,您可以通过将globals()['Test']转换为虚线名称来实现此目的。以下示例应该有效:

g = globals()
@g.get('Test')
def Fun(self):
    pass

x = globals()['Test']
@x
def Fun(self):
  pass

或者,正如您所注意到的,您可以跳过语法糖并手动装饰,这可能是最不好的选择。

答案 1 :(得分:0)

因为Python解析器不是为了将索引访问识别为装饰器语法的一部分而设计的。考虑编写一个单独的函数来代替访问globals()