2016-04-27 12 views
0

私はクロージャがPythonでどのように動作するかを理解しようとしています。Pythonのクロージャー - ローカル変数が代入の前に参照されています

add1はここでうまく動作するはずです。 helperが呼び出されたときに変数xが定義されていると思います。しかし、それは私にLocal variable referenced before assignmentエラーを与えています。

add2は、add1と非常に似ています。 xに整数を代入するのではなく、xに整数を代入します。それの振る舞いは、私が期待しているものと一直線に並んでいます。 xが定義され、参照可能な内部はhelperです。

import random 

def add1(): 
    x = 0 
    def helper(): 
     x = x + 1 
     return x 
    return helper 

def add2(): 
    x = {} 
    def helper(): 
     x[random.randint(1,1000)] = 3 
     return x 
    return helper 

if __name__ == '__main__': 
    a1 = add1() 
    a2 = add2() 

    # print(a1()) #This causes error 
    print(a2()) #{650: 3} 
    print(a2()) #{650: 3, 333: 3} 

これの背後にある論理は何ですか? xの種類が異なる以外は、私は何をしていますか?

+0

あなたは関数リファレンスを返していますが、実際にはヘルパーは実際には呼び出されません。 – TigerhawkT3

+0

それを変更しても、毎回新しい辞書 'x'が定義されているので、その後の' a2() 'の呼び出しで追加のキーと値のペアを得ることはありません。 – TigerhawkT3

+0

@ TigerhawkT3「どちらもヘルパーが実際に呼ばれていない」ということについてもっと詳しく説明できますか?それが呼び出されない場合、なぜ呼び出す 'a2'は毎回新しい値を辞書に追加しますか? – denniss

答えて

4

変数がクロージャの外側にバインドされていることをコンパイラが認識することを期待しています。これは真実ではないので、これを示すにはnonlocalを使用する必要があります。 dennissにより

def add1(): 
    x = 0 
    def helper(): 
     nonlocal x 
     x = x + 1 
     return x 
    return helper 

EDIT:それだけで(別名、それを再割り当てしない)を再結合xを変更していないので

nonlocal

add2に必要ではありません。一方、add1では、x= x+1re-assignmentです。

+0

と私は 'add2'のためにこれを行う必要はありませんか? – denniss

+0

'add2()'で 'x'を再バインドしないので、あなたはそれだけを変更します。 –

+1

!!!!!!!!!!!! GOTCHA ...あなたの答えにその最後の詳細を追加してください....私は他のpplがそれを見ることを確認したい。 – denniss

関連する問題