2016-09-24 12 views
1

編集:私は自分の質問を説明してくれました。私はどのようにクロージャで、その関数は、以前の環境を覚えているようだが混乱していたが、再帰呼び出しでは、名前の更新値を見つけるようだ。私の混乱再帰関数をデコレートする

Thomas Ballinger "Finding closure with closures" talkによって完全に解決されました:変数の

スコープ定義で決定され、変数の値は、実行時に決定されます。

再帰またはクロージャのいずれかを使用すると、名前のバインディングが定義時に定義されましたが、値はその後でも更新できます。

オリジナル質問:

デコレータは、余分な努力なしに再帰関数では動作:

def debug(f): 
    def new_f(*args, **kwargs): 
     print('arguments:', *args, **kwargs) 
     return f(*args, **kwargs) 
    return new_f 

@debug 
def f(n): 
    if n > 1: 
     return f(n-1)*n # f refers to the decorated version! 
    else: 
     return 1 
ではなくラインで fその return f(n-1)*nポイント fの装飾が施されたバージョンに確実にPythonでどのようなメカニズム

元の?

私は関数が定義された時点でそのコンテキストを記憶していると考えました(つまり、クロージャでは、内部関数は外部関数のオブジェクトを使用できます)。しかし、fが定義されたときに、デコレータがまだ適用されていなかったので、fの中にの機能fは永遠に装飾されていないバージョンを参照していますか?明らかに、私は関数スコープ/文脈規則で何かを誤解しましたが、何ですか?

+1

他の場所を指すようにするメカニズムが欠けています。 '@ debug'は、' f = debug(f) 'を呼び出す関数を定義する構文的な砂糖であることを覚えておいてください。 – jonrsharpe

答えて

2

機能がときPythonは名前fを検索するという事実は、(とないそれはそれをコンパイル)を実行し、それが装飾されたバージョンであることがわかります。nameので

>>> f 
<function __main__.debug.<locals>.new_f> 

fは、デコレータを適用することによって本質的に再バインドされます。つまり、名前が検索されるたびに使用されるfです。

+0

ありがとうございます。しかし、閉鎖の内部機能はどうでしょうか?内部関数の定義ではなく、内部関数の名前に基づいてオブジェクトにリンクする方法はありますか? – max

+0

私のコメントへの答えは私の質問の編集です。 – max