我试图在这里找到答案,但不能。
@obj.func # works
@obj.func(**kwargs) #works
@obj.func1(**kwargs).func2 #-> syntax error
我不明白为什么第三种形式是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
您可以使用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
但是为什么这个以下'捷径语法'被禁止:
@redcross.copy(color="blue").caller
def plot_data2(**kwargs):
pass
但我能做到:
@redcross.copy_and_decorate(color="blue")
def plot_data2(**kwargs):
pass
第一种形式看起来更好,至少我更了解背后的意图。
答案 0 :(得分:6)
Function definitions grammar不允许使用更多虚线名称进行调用;语法仅限于虚线名称和末尾的可选调用 :
decorated ::= decorators (classdef | funcdef)
decorators ::= decorator+
decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE
funcdef ::= "def" funcname "(" [parameter_list] ")" ":" suite
dotted_name ::= identifier ("." identifier)*
请注意,不是一个完整的表达式,而是一个非常有限的子集。
这与PEP相呼应,其中指出:
装饰器语句受限于它可以接受的内容 - 任意表达式都不起作用。 Guido更喜欢这种,因为有一种直觉[17]。
和
使用返回装饰器的函数的基本原理是@符号后面的部分可以被认为是表达式(虽然在语法上仅限于一个函数),并且该表达式返回的任何内容叫做。参见声明参数[16]。
强调我的。
理由是Guido feels there isn't a real use case for allowing more:
因此,虽然将语法更改为@test非常容易 未来,我想坚持使用更受限制的形式,除非是真实的 提供用例,允许@test提高可读性。 (@foo()。bar()不算数,因为我不指望你需要 这一点)。
你必须说服Guido和其他核心开发人员,你的案例是一个值得解除这些限制的正确用例!
答案 1 :(得分:0)
如另一个答案所述,Guido had a "gut feeling"最初是受到限制的原因。
Python 3.9中取消了此限制。,允许装饰器成为任何有效的表达式。
Previously, the grammar对于装饰器是:
decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
在Python 3.9中,the grammar简化为:
decorator: '@' namedexpr_test NEWLINE
这是3.8和3.9之间的唯一语法更改。有关详细信息,请参见PEP 614 -- Relaxing Grammar Restrictions On Decorators。