46

次の Python コードでは、UnboundLocalError. 私が理解しているように、ローカル関数はそれを含む関数のローカル変数を共有しますが、これはほとんど当てはまらないようです。このコンテキストでは不変の値であることは認識してaいますが、問題にはなりません。

def outer():
    a = 0
    def inner():
        a += 1
    inner()
outer()

の値が可変型でラップされているUnboundLocalError場合は例外が発生しないため、内部関数は親関数のすべての参照のコピーを受け取ったようです。a

誰かがここで動作を明確にし、これに関する適切な Python ドキュメントを教えてくれますか?

4

3 に答える 3

38

これを「可変性」の問題と見なすのは正しいと思います。投稿したコードは「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" を変更できます (このセットアップでのテストでおそらく気付いたように)。

それが役立つことを願っています!

于 2009-09-12T04:54:30.797 に答える
19

クロージャ内の状態を保持するために、変数を非ローカルとして指定する必要があるため、定義は次のようになります。

def outer():
    a = 0
    def inner():
        nonlocal a
        a += 1
    inner()
于 2013-03-11T08:41:38.220 に答える
11

変数を引数としてバインドしてみてください。

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()
于 2009-09-12T04:55:11.733 に答える