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,就会报错,为什么?
PHP中文网2017-04-18 09:31:09
実際、この問題は、変数によって参照されるオブジェクトが可変であるか不変であるかという問題は脇に置くことができます。注意する必要があるのは、変数の の位置、つまり変数の時点と範囲です。定義。
次のコードを考えてみましょう:リーリー
このコードはエラーをスローします:リーリー
は関数 a
の param 変数なのでローカル変数に属し、スコープは test
関数内で参照するので、大きな問題はありません。 test
と。 print(a)
しかし、
は最初から最後までLEGB原則に従って検索しても見つからないので、b
を上げます。 NameError
リーリー
よし、今回は問題ないようです。Python はグローバルのスコープ内で を見つけました。Python がグローバル b
を使用する理由は、ローカルに b
を定義していないからです。 b
リーリー
結果:リーリー
関数内の 2 つの は 1 と 20 を出力しましたが、関数を終了した後に出力された 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
結論
global
で指定されていないかを確認してください。
global
nonlocal
: Python-QA
PHP中文网2017-04-18 09:31:09
Python の変数スコープはこのように規定されており、test1 では print x
はできますが、x を変更することはできません
「ローカルスコープのグローバル変数は読み取り専用であるべきだ」という人もいますが、これは当てはまりません。この条件を参照します。 。 。
Python のこの場所は本当にわかりにくいです
天蓬老师2017-04-18 09:31:09
簡単に言えば、ローカル スコープではグローバル変数のバインディングを変更できません。また、CPython
では変数のアドレスを変更できません。
参照: よくある間違い 4: Python プログラマーが犯す 10 の最も一般的な間違い: Python での変数名の解析の誤解
伊谢尔伦2017-04-18 09:31:09
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
がエラー