次のPythonコードで、UnboundLocalError
を取得します。私が理解しているように、ローカル関数はそれを含む関数のローカル変数を共有しますが、ここではそうではないようです。私はa
がこのコンテキストでは不変の値であることを認識していますが、それは問題にはなりません。
def outer():
a = 0
def inner():
a += 1
inner()
outer()
UnboundLocalError
の値が可変タイプにラップされている場合、a
例外が発生しないため、内部関数は親関数のすべての参照のコピーを受け取ったように見えます。
誰かがここで動作を明確にして、適切なPythonのドキュメントをこれに示すことができますか?
これを「可変性」の問題と見なすことは正しいと私は思います。投稿したコードは「UnboundLocalError」をスローしますが、次のコードはスローしません。
def outer():
a = 0
def inner():
print a
inner()
outer()
Pythonでは、内部スコープの外部スコープから変数の値を再割り当てすることはできません(この場合は適用されないキーワード「global」を使用している場合を除く)。
このPython 2.6.2ドキュメントの「クラス」ドキュメントの下部セクションをチェックしてください:
9.2。Pythonスコープと名前空間
[…]名前がグローバルとして宣言されている場合、すべての参照と割り当ては、モジュールのグローバル名を含む中間スコープに直接移動します。それ以外の場合、最も内側のスコープの外側にあるすべての変数は読み取り専用です(そのような変数に書き込もうとすると、同じ名前の外側の変数は変更されないまま、最も内側のスコープに新しいローカル変数が作成されます)。
「UnboundLocalError」は、関数が実際に「a」という新しい変数を宣言し、すぐに「+ =」操作を実行しようとしているためですが、「a」にはまだ値がないため、これは失敗します。 (「a + = 1」を「a = a + 1」として表示すると、「a」が未定義の場合に問題を確認できます)。
一般に、「a」を変更する場合、人々が通常それを回避する方法は、可変リストを使用して「a」を渡すことです(リストや辞書など)。変更可能な型のコンテンツを介して「a」を変更できます(この設定でのテストでおそらく気づいたでしょう)。
お役に立てば幸いです。
変数を非ローカルとして指定して、クロージャの状態を保持する必要があるため、定義は次のようになります。
def outer():
a = 0
def inner():
nonlocal a
a += 1
inner()
変数を引数としてバインドしてみてください。
def outer():
a = 0
def inner(a=a):
a += 1
inner()
outer()
適切なドキュメントを探して掘り下げます。
編集
内部関数は外部スコープに副作用を持たせたいので、リストのような変更可能なデータ型を使用する必要があります。整数と文字列は不変です。
def outer():
a = [0]
def inner():
a[0] += 1
inner()
print a[0]
outer()