Python decorator @func (). Attribute syntax error.

I tried to find the answer here, but could not.

@obj.func # works @obj.func(**kwargs) #works @obj.func1(**kwargs).func2 #-> syntax error 

I don’t understand why the third form is SyntaxError, it seems to me that this does not violate the python syntax, and it is clear to me what the user wants to do (see the example below).

I looked at pep 0318 decorator implementations, but could not find the answers.

The following is an example of use:

 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 

How can you use ItemFunc as a decorator:

 @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 

But why is this following "short syntax" forbidden:

 @redcross.copy(color="blue").caller def plot_data2(**kwargs): pass 

But I can do:

 @redcross.copy_and_decorate(color="blue") def plot_data2(**kwargs): pass 

The first form looks better, at least I better understand the intentions.

+5
source share
1 answer

The function definition verb does not allow calls with more precise names; the syntax is limited to name points and an optional call at the end:

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

Note that this is not a complete expression, but a very limited subset.

This has something in common with PEP, which reads:

The decorator's statement is limited by what it can accept - arbitrary expressions will not work. Guido preferred this because of the gut feeling [17].

and

The rationale for having a function that returns a decorator is that the part after the @ sign can be considered an expression (although it is syntactically limited only to the function) , and everything that returns this expression is called. See Declarative Arguments [16].

Emphasis is mine.

The rationale is that Guido believes that there is no real use case for resolving more :

So, although it would be fairly easy to change the syntax to @test in the Future, I would like to stick to a more limited form if there is a use case that allows @test to increase readability. (@foo (). bar () is not taken into account, because I do not expect you to ever need that).

You will need to convince Guido and other kernel developers that your case is the proper tool worthy of lifting these restrictions!

+6
source

All Articles