2015-09-14 9 views
5

私はここで答えを見つけようとしましたが、できませんでした。三番目の形式はでSyntaxErrorである理由私は理解していないPythonデコレータ@func()。属性の構文エラー

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

は、それはそれは任意のPythonの構文に違反していないと、ユーザーが何をしたいのか私には明らかである私のためと思われる(以下の例を参照)。

私はデコレータの実装のpep 0318を見ましたが、何の答えも見つかりませんでした。ここで

怒鳴る、使用例のようになります。これ以下の「ショートカット構文は」禁止されている理由

@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 

をしかし:あなたはデコレータとしてItemFuncを使用することができるよりも

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 

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

しかし、私はできる:

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

最初の形式はより良いものを探しますが、少なくとも私は後ろの意図をよく理解しています。

答えて

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]を参照してください。

強調鉱山。それは 将来的に@Testする構文を変更することが非常に簡単になりながら

だから、私は本当の ない限り、より制限された形に固執したいと思います:

根拠はGuido feels there isn't a real use case for allowing moreということです@testを許可すると可読性が向上するユースケースが提示されます。 (@foo()。bar()はカウントされません。なぜなら、私はあなたがこれまでに を必要とするとは思わないからです)。

あなたは、あなたのケースがこれらの制限を解除するのにふさわしい適切な使用法であると、Guidoと他のコア開発者に納得させる必要があります。

+0

ええ、それはもっと哲学的な問題です。 getterや.callerのようなものでデコレータを完成させる私の場合(私の例のように)、最終的に.callerメソッドを送信する関数を呼び出しながら、私たちがやりたいことを明確にしています。読める。あなたは思いませんか? – user3240484

+0

@ user3240484:セットアップでどこに行くのか分かります。属性を使用する代わりに '__call__'が実際のデコレータを返すようにしてください。これは' __call__'もサポートしていますか? –

+0

あなたは正しいですが、私の例を見れば、__call__メソッドはすでにオブジェクトのようにオブジェクトのように 'fcall'関数のデコレータのように動作しています。私は__call__を呼び出し関数で置き換え、__call__を使ってデコレータを返すことができましたが、私がそこで得るものはそこにあります。ありがとう – user3240484