x = 3
y = [3]
def test1():
x += 1
print x
def test2():
y[0] = 4
y.append(5)
print y
test2()
test1()
这段代码执行结果: test2()成功打印[4, 5], test1()却报错: UnboundLocalError: local variable 'x' referenced before assignment
想不明白,为什么会这样,全局变量在函数里可以直接打印,但是如果要改变它的值,会报错,但是test2()为什么不报错?如果把y换成dict类型,就能在函数里不需要用global声明,可以直接改变y的值,但如果是str或number,就会报错,为什么?
実際、この問題は、変数によって参照されるオブジェクトが可変であるか不変であるかという問題は脇に置くことができます。注意する必要があるのは、変数の の位置、つまり変数の時点と範囲です。定義。
次のコードを考えてみましょう:リーリー
このコードはエラーをスローします:リーリー
は関数
この問題を解決するには、グローバル変数を定義できるかもしれません:a
の param 変数なのでローカル変数に属し、スコープはtest
関数内で参照するので、大きな問題はありません。test
と。print(a)
しかし、は最初から最後までLEGB原則に従って検索しても見つからないので、
b
を上げます。NameError
リーリー
よし、今回は問題ないようです。Python はグローバルのスコープ内でを見つけました。Python がグローバル
次に、関数内で変数の割り当てを開始します。b
を使用する理由は、ローカルにb
を定義していないからです。b
リーリー
結果:リーリー
関数内の 2 つのは 1 と 20 を出力しましたが、関数を終了した後に出力された
ローカル変数が定義されていない場合、Python は自動的にグローバル変数を使用しますが、それ以外の場合は使用しません キーワードの助けが必要です:print
の値が 100 になったのはなぜですか?b
関数 A でこれを書いたからですassign は 定義 でもあるため、
b = 20
にあるtest
はすべてローカルであり、グローバルではありません。そのため、b
に加えた変更はグローバル 。b
b
これは次のことを意味します:リーリー リーリー
を記述するglobal
キーワードを使用すると、Python は
リーリーglobal
内のb
をグローバルtest
にアクセスするための変数として扱い、b
は代入アクションが定義されないものとしてのみ扱われます。新しいローカル変数。b
b = 20
さらに混乱を招く例を見てみましょう:結果:
リーリーが
に表示されていますが、なぜこれが起こっているのでしょうか? 理由は非常に単純です。にはこの関数
リーリーUnboundLocalError
に代入アクションと定義アクションがあるため、b
内のb = 20
はローカル (グローバル) です。test
がグローバルであることを示すためにここでは使用されていません)。そのため、b
が使用されると、Python はグローバルb
ではなくローカルprint(b)
を取得しようとしますが、悲劇的なのは、最初のステップでローカルb
は代入されていないので、代入される前にb
が参照されていると言われますが、当然あり得ません。b
local variable 'b' referenced before assignment
あなたが挙げた例を振り返ってください:ここで、
したがって、等号の右側にあるtest1
の定義はx
内にあります (グローバルはなく、x
は等号の左側に表示されます)。ローカルを使用しますが、理由:x
リーリーによって参照される値を取得したい場合、その値にはまだ値が割り当てられていないことがわかります。これは上記の例と同じです。
あなたのx
リーリーについては問題ありません:
は、test2
リーリーの等号の左側に y が表示されないため、Python は自動的にグローバル
test2
が使用されているとみなします。したがって、当然問題はありません。y
結論関数内でローカル変数が定義されているかどうかを確認するには、変数名が等号の左側に表示されているかどうか、また変数名が
ローカル変数が定義されている場合、Python はグローバル変数を検索しません。それ以外の場合、Python は自動的にグローバル変数を使用します
ローカル変数が定義されているが、変数が割り当てられる前に参照を読み取る場合、UnboundLocalError が表示されます
この問題を解決するには、ドメイン全体を示す - を忘れずに追加してください。そうでない場合、この書き込みメソッドは表示されません (インプレース操作、または後で代入)
同様の問題はローカル関数でも発生しますが、解決策は - (Python3) を追加することですが、それはまた別の話です。
global
で指定されていないかを確認してください。global
nonlocal
私が回答した質問
: Python-QA
Python の変数スコープはこのように規定されており、test1 では
print x
はできますが、x を変更することはできません「ローカルスコープのグローバル変数は読み取り専用であるべきだ」という人もいますが、これは当てはまりません。この条件を参照します。 。 。
Python のこの場所は本当にわかりにくいです
簡単に言えば、ローカル スコープではグローバル変数のバインディングを変更できません。また、
CPython
では変数のアドレスを変更できません。参照: よくある間違い 4: Python プログラマーが犯す 10 の最も一般的な間違い: Python での変数名の解析の誤解
test1
関数には代入操作x += 1
があり、Python インタプリタによって関数のローカル スコープ内の変数と見なされますが、変数x
は代入前に定義されていません。x
はnumber
であり、不変型に新しい値を割り当てるには、不変型オブジェクトを再作成し、元の変数を新しく作成したオブジェクトにリダイレクトする必要がありますが、これは新たに行われます。作成されたオブジェクトはLEGB
に含まれていません。見つからないため、エラーが報告されますtest2
関数では、y
は変数型であるlist
です。これは、リストが変数型であり、その場で変更できるためです。 、エラーは報告されませんPython
のすべての代入操作は、基本的に次の 3 つのステップに分かれています (a = 3
を例にします):値を表すオブジェクトを作成します
3
変数
a
がまだ作成されていない場合は作成します変数
a
を新しいオブジェクト3
リーリーtest2
関数の実行中に変数y
のメモリ アドレスの変化を観察してみましょう出力
リーリー
を報告する理由も説明できます。y
が実際にその場で変更されることがわかります。そのため、変数を繰り返し作成する必要はありません。また、x
不変型に値を割り当てるには、まず新しいオブジェクトを作成する必要があります。名前が同じであっても、毎回異なる割り当てが行われる場合、x
のメモリ アドレスは実際には異なることがわかります。これは、str
またはnumber
がエラー