関数内のifステートメントの条件でグローバル変数が使用されると、PythonはUnboundLocalErrorをスローします

サルサックスリ

変数がグローバルスコープで宣言されているにもかかわらず、UnboundLocalErrorが発生します。この特定のステートメントでは、変数がローカル変数であると想定/強制されているように見えます。

ifステートメント条件内の変数が異なる方法で処理される理由がわかりません。誰かが何が起こっているのか説明できますか?

次のスニペットは、私がやろうとしていたことの簡単な例です。

In [1]:  global mock
...      mock = False
...
...
...      def foo():
...          if not mock:
...              # do stuff
...              mock = True
...
...          # do other stuff
...
...
...      foo()

これにより、関数宣言のすぐ上でグローバルboolが宣言されているにもかかわらず、UnboundLocalErrorがスローされます。

---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
<ipython-input-31-540737067cb1> in <module>()
      7 
      8 
----> 9 foo()

<ipython-input-31-540737067cb1> in foo()
      3 
      4 def foo():
----> 5     if not mock:
      6         mock = True
      7 

UnboundLocalError: local variable 'mock' referenced before assignment

ただし、このスニペットは期待どおりに実行されます。

In [2]:  mock = False
...
...
...      def bar():
...          return mock
...
...
...      bar()

Out[2]:  False

同様に、ifステートメントの本体に変数​​を含むこのスニペットも期待どおりに実行されます。

In [3]:  mock = False
...
...
...      def foobar():
...          if True:
...              return mock
...
...          return True
...
...
...      foobar()

Out[3]:  False

ドキュメント(https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespacesでスコープと名前空間に関する次の記事を見つけましたが、に基づいて期待どおりに機能するはずだと思います以下、

スコープは静的に決定されますが、動的に使用されます。実行中はいつでも、名前空間に直接アクセスできるネストされたスコープが少なくとも3つあります。

  • 最初に検索される最も内側のスコープには、ローカル名が含まれます
  • 最も近い囲みスコープから検索される囲み関数のスコープには、非ローカル名だけでなく非グローバル名も含まれます
  • 最後から2番目のスコープには、現在のモジュールのグローバル名が含まれます
  • 最も外側のスコープ(最後に検索)は、組み込み名を含む名前空間です

Windows10のConda内でPython3.6.6およびIPython6.5.0でJupyter4.4.0を使用していましたが、コンソールIPythonおよびPython3.6.0を実行するIDLE3.6.0GUIでこの動作を再現できます。

編集:どういうわけか、次のスニペットは影響を受けませんか?これは、同じ内の変数の更新に関連しているようです。この時点で、些細なことを見逃しているに違いないと思います。

In [4]:  global mock # also works without this line
...      mock = False
...
...
...      def foo1():
...          if not mock:
...              return mock
...
...          return True
...
...
...      foo1()

Out[4]:  False
アンソニー・ソッティル

変数は関数スコープです。関数内に名前への割り当てがあるためmock、へのすべての参照mockは「ローカル」として試行されます(実際には別のオペコードにコンパイルされます!)

global mock関数でを使用してこれを変更できます(したがって、割り当てと参照はグローバルに強制されます

def foo():
    global mock
    if not mock:
        mock = true

最初の例global mockでは、モジュールスコープで記述したことに注意してください-これは何もしません:)

分解を直接見る方が理にかなっているかもしれません。

>>> import dis
>>> def f():
...     if not mock:
...         mock = True
...
>>> dis.dis(f)
  2           0 LOAD_FAST                0 (mock)
              3 POP_JUMP_IF_TRUE        15

  3           6 LOAD_GLOBAL              0 (True)
              9 STORE_FAST               0 (mock)
             12 JUMP_FORWARD             0 (to 15)
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE
>>> def g():
...     global mock
...     if not mock:
...         mock = True
...
>>> dis.dis(g)
  3           0 LOAD_GLOBAL              0 (mock)
              3 POP_JUMP_IF_TRUE        15

  4           6 LOAD_GLOBAL              1 (True)
              9 STORE_GLOBAL             0 (mock)
             12 JUMP_FORWARD             0 (to 15)
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

Related 関連記事

ホットタグ

アーカイブ