2016-12-01 8 views
2

をだから私はこのコードを持っている:機能属性 - 範囲

def collect_input(func): 
    """ 
    A decorator which adds an all_input attribute to the wrapped function. 
    This attribute collects any input passed to the function. 
    """ 
    def wrapper(*args, **kwargs): 
     wrapper.all_input.append(*args) 
     return func(*args, **kwargs) 

    wrapper.all_input = [] 
    return wrapper 

@collect_input 
def foo(bar): 
    print('in foo') 

foo(5) 
foo('spam') 

print(foo.all_input) 

私の質問は:なぜあなたはfoo.all_inputにアクセスすることができ、それはcollect_inputスコープで宣言されている場合は?

+0

の場所を取る方法を見ることができますこれは 'wrapper'関数を返します。 – Kasramvd

答えて

2

Pythonの素晴らしい点は、オブジェクトを評価するための一連のルールがあり、これらのルールにはほとんど例外がないことです。

この場合、装飾される関数は通常のPythonオブジェクトに過ぎません。あるものは呼び出し可能でもあります。 wrapperという名前のその時点で - - collect_input内側の線wrapper.all_input = []に何が起こる

は、オブジェクトの属性を設定していることですが、返され、グローバルスコープでfoo機能の場所を取ることになる目的です。それがデコレータの仕組みです。

だから、可能な限り明確にするためにステップバイステップの谷しまったことができます:

  1. 上記のコードを実行している場合は、collect_input機能を定義 - デコレータとして使用するように設計されています。

  2. 次に、foo関数を定義しますが、グローバルスコープに追加する前に、関数collect_inputに渡されます。それは "@"構文がするものです。関数が存在する前に、最初に関数を定義するための関数をデコレートしてから、それをデコレータの戻り値に置き換えて通常の代入で置き換えます。だから、上記のコードは同じです:

    デフのfoo(...): ...

    のfoo = collect_input(FOO)

  3. インサイド "collect_input"、オリジナルfoo FUNC新しいwrapper関数内で呼び出されます。このwrapper関数:デコレータcollect_inputが呼び出されるたびに作成される新しい(関数)オブジェクトは、最も外側のfooの定義に代わるオブジェクトです。 wrapperのコードの中には、collect_inputが意味するものを正確に行うための特別なコードがあります。この場合、入力パラメータをリストに注釈を付けて元の関数 - fooに再開します。

  4. は最後にcollect_inputによって返されるwrapperオブジェクトがfooの場所がかかりますが、デコレータの呼び出し内のそれに添付all_inputsリストを持っています。したがって、定義されている場所に関係なく、fooオブジェクトの属性としてグローバルスコープでアクセスできます。関数の外では、期待どおりにfuncまたはwrapperという名前を使用できないことに注意してください。

1
@collect_input 
def foo(bar): 
    print(foo.__name__) # wrapper 
    print('in foo') 

あなたはwrapperあなたはデコレータを使用して機能を包みましたので、実際には、あなたが `foo.all_input`が、` wrapper.all_input`にアクセスしていないfoo

関連する問題