Python装饰器@func().属性语法错误

use*_*484 5 python attributes class decorator python-decorators

我试图在这里找到答案,但不能.

@obj.func # works
@obj.func(**kwargs)  #works
@obj.func1(**kwargs).func2   #-> syntax error 
Run Code Online (Sandbox Code Playgroud)

我不明白为什么第三种形式是SyntaxError,对我来说似乎没有违反任何python语法,我很清楚用户想要做什么(见下面的例子).

我看了装饰器实现的pep 0318,但没有找到任何答案.

下面,这将是一个使用的例子:

class ItemFunc(object):
    def __init__(self, fcall=None, **kwargs):
        self.defaults = kwargs
        self.fcall = None

    def __call__(self, *args, **kwargs):
        kwargs = dict(self.defaults, **kwargs)
        # do something more complex with kwargs 
        output = self.fcall(*args, **kwargs)
        # do something more with output  
        return output

    def caller(self, fcall):
        """ set call and return self """
        self.call = fcall # after some check obviously
        return self

    def copy(self,**kwargs):
        kwargs = dict(self.defaults, **kwargs)
        return self.__class__(self.fcall, **kwargs)

    def copy_and_decorate(self, **kwargs):
        return self.copy(**kwargs).caller 
Run Code Online (Sandbox Code Playgroud)

你可以使用ItemFunc作为装饰器:

@ItemFunc
def plot(**kwargs):
    pass

redcross = plot.copy(color="red", marker="+")
@redcross.caller
def plot_data1(**kwargs):
    pass

bluecross = redcross.copy(color="blue")
@bluecross.caller
def plot_data2(**kwargs):
    pass
Run Code Online (Sandbox Code Playgroud)

但为什么禁止遵循"捷径语法":

@redcross.copy(color="blue").caller
def plot_data2(**kwargs):
    pass
Run Code Online (Sandbox Code Playgroud)

但我能做到:

@redcross.copy_and_decorate(color="blue")
def plot_data2(**kwargs):
    pass         
Run Code Online (Sandbox Code Playgroud)

第一种形式看起来更好,至少我更了解背后的意图.

Mar*_*ers 6

函数定义语法不允许进一步带点名称电话; 语法仅限于带点名称和一个可选的通话:

decorated      ::=  decorators (classdef | funcdef)
decorators     ::=  decorator+
decorator      ::=  "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
funcdef        ::=  "def" funcname "(" [parameter_list] ")" ":" suite
dotted_name    ::=  identifier ("." identifier)*
Run Code Online (Sandbox Code Playgroud)

请注意,这不是一个完整的表达式,而是一个非常有限的子集.

这与PEP相呼应,其中指出:

装饰器语句受限于它可以接受的内容 - 任意表达式都不起作用.Guido更喜欢这种,因为有一种直觉[17].

使用返回装饰器的函数的基本原理是@符号后面的部分可以被认为是一个表达式(虽然在语法上仅限于一个函数),并且调用该表达式返回的任何内容.参见声明参数[16].

强调我的.

理由是Guido认为没有一个真正的用例允许更多:

因此,虽然将来很容易将语法更改为@test,但我还是要坚持使用更受限制的形式,除非提供真正的用例,允许@test提高可读性.(@foo().bar()不算数,因为我不指望你曾经需要那个).

您必须说服Guido和其他核心开发人员,您的案例是一个值得解除这些限制的正确用例!