検索

ホームページ  >  に質問  >  本文

python的作用域问题

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,就会报错,为什么?

高洛峰高洛峰2889日前759

全員に返信(4)返信します

  • PHP中文网

    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これは次のことを意味します:

    ローカル変数が定義されていない場合、Python は自動的にグローバル変数を使用しますが、それ以外の場合は使用しません

    それでは、関数内でグローバル変数を操作するにはどうすればよいでしょうか?これには、
    キーワードの助けが必要です:

    リーリー リーリー 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結論

      関数内でローカル変数が定義されているかどうかを確認するには、変数名が等号の左側に表示されているかどうか、また変数名が
    1. global で指定されていないかを確認してください。

    2. ローカル変数が定義されている場合、Python はグローバル変数を検索しません。それ以外の場合、Python は自動的にグローバル変数を使用します
    3. ローカル変数が定義されているが、変数が割り当てられる前に参照を読み取る場合、UnboundLocalError が表示されます
    4. この問題を解決するには、ドメイン全体を示す
    5. を忘れずに追加してください。そうでない場合、この書き込みメソッドは表示されません (インプレース操作、または後で代入)

      global

    6. 同様の問題はローカル関数でも発生しますが、解決策は
    7. (Python3) を追加することですが、それはまた別の話です。

      nonlocal


    私が回答した質問

    : Python-QA

    返事
    0
  • PHP中文网

    PHP中文网2017-04-18 09:31:09

    Python の変数スコープはこのように規定されており、test1 では print x はできますが、x を変更することはできません
    「ローカルスコープのグローバル変数は読み取り専用であるべきだ」という人もいますが、これは当てはまりません。この条件を参照します。 。 。

    Python のこの場所は本当にわかりにくいです

    返事
    0
  • 天蓬老师

    天蓬老师2017-04-18 09:31:09

    簡単に言えば、ローカル スコープではグローバル変数のバインディングを変更できません。また、CPython では変数のアドレスを変更できません。

    参照: よくある間違い 4: Python プログラマーが犯す 10 の最も一般的な間違い: Python での変数名の解析の誤解

    返事
    0
  • 伊谢尔伦

    伊谢尔伦2017-04-18 09:31:09

    test1 関数には代入操作 x += 1 があり、Python インタプリタによって関数のローカル スコープ内の変数と見なされますが、変数 x は代入前に定義されていません。 xnumber であり、不変型に新しい値を割り当てるには、不変型オブジェクトを再作成し、元の変数を新しく作成したオブジェクトにリダイレクトする必要がありますが、これは新たに行われます。作成されたオブジェクトは LEGB に含まれていません。見つからないため、エラーが報告されます

    test2 関数では、y は変数型である list です。これは、リストが変数型であり、その場で変更できるためです。 、エラーは報告されません

    Python のすべての代入操作は、基本的に次の 3 つのステップに分かれています (a = 3 を例にします):

    1. 値を表すオブジェクトを作成します3

    2. 変数 a がまだ作成されていない場合は作成します

    3. 変数 a を新しいオブジェクト 3

    4. に接続します

    test2 関数の実行中に変数 y のメモリ アドレスの変化を観察してみましょう

    リーリー

    出力

    リーリー

    y が実際にその場で変更されることがわかります。そのため、変数を繰り返し作成する必要はありません。また、x 不変型に値を割り当てるには、まず新しいオブジェクトを作成する必要があります。名前が同じであっても、毎回異なる割り当てが行われる場合、x のメモリ アドレスは実際には異なることがわかります。これは、str または number がエラー

    を報告する理由も説明できます。

    返事
    0
  • キャンセル返事