Pythonはローカル変数領域でコードを実行します。


問題
使用範囲内でコードセグメントを実行したいです。実行後の結果は全部見えません。
ソリューション
この問題を理解するために、簡単なシーンを試してみます。まず、グローバル名前空間でコードセグメントを実行します。

>>> a = 13
>>> exec('b = a + 1')
>>> print(b)
14
>>>
そして、もう一つの関数で同じコードを実行します。

>>> def test():
...   a = 13
...   exec('b = a + 1')
...   print(b)
...
>>> test()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in test
NameError: global name 'b' is not defined
>>>
最後にNameErrer異常を投げたのはexec() 文で実行したことがないのと同じです。後の計算にexec() を使って結果を実行したいなら問題があります。
このようなエラーを修正するためには、 exec() を呼び出す前に locals() 関数を使ってローカル変数辞書を得る必要があります。その後、一部の辞書から修正後の変数値を取得できます。たとえば:

>>> def test():
...   a = 13
...   loc = locals()
...   exec('b = a + 1')
...   b = loc['b']
...   print(b)
...
>>> test()
14
>>>
討論する
実際に exec() の正しい使い方は難しいです。ほとんどの場合、exec() を使うことを考慮すると、他にもっと良い解決策があります。
しかし、もしあなたがまだexec()を使うなら、このセクションでは正しい使い方をいくつか示しています。デフォルトでは、exec()は、コーディネーターのローカルとグローバル範囲内でコードを実行します。しかし、関数内では、exec()に伝達される部分範囲は、実際の局所変数からなる辞書をコピーすることである。したがって、exec()が修正操作を行うと、この修正結果は実際の局所変数値に影響を及ぼさない。これはもう一つのプレゼンテーションの例です。

>>> def test1():
...   x = 0
...   exec('x += 1')
...   print(x)
...
>>> test1()
0
>>>
上のコードでは、 locals() を呼び出してローカル変数を取得すると、 exec() に渡されるローカル変数のコピーが得られます。コード実行後にこの辞書の値を審査することで、修正後の値を取得することができます。以下はデモの例です。

>>> def test2():
...   x = 0
...   loc = locals()
...   print('before:', loc)
...   exec('x += 1')
...   print('after:', loc)
...   print('x =', x)
...
>>> test2()
before: {'x': 0}
after: {'loc': {...}, 'x': 1}
x = 0
>>>
最後のステップの出力をよく観察してください。locで修正された値を手動でxに割り当てない限り、x変数の値は変わりません。 locals() を使う時、操作の順序に注意しなければなりません。呼び出される度に、locals() は、ローカル変数値の値を取得し、辞書内の対応する変数をカバーする。以下の試験の出力結果を確認してください。

>>> def test3():
...   x = 0
...   loc = locals()
...   print(loc)
...   exec('x += 1')
...   print(loc)
...   locals()
...   print(loc)
...
>>> test3()
{'x': 0}
{'loc': {...}, 'x': 1}
{'loc': {...}, 'x': 0}
>>>

>>> def test3():
...   x = 0
...   loc = locals()
...   print(loc)
...   exec('x += 1')
...   print(loc)
...   locals()
...   print(loc)
...
>>> test3()
{'x': 0}
{'loc': {...}, 'x': 1}
{'loc': {...}, 'x': 0}
>>>
注意最後にlocals() を呼び出した時のxの値はどうやって上書きされますか? locals() の代替案として、自分の辞書を使ってexec() に渡すことができます。たとえば:

>>> def test4():
...   a = 13
...   loc = { 'a' : a }
...   glb = { }
...   exec('b = a + 1', glb, loc)
...   b = loc['b']
...   print(b)
...
>>> test4()
14
>>>
ほとんどの場合、この方法はexec() を使用する最良の実践である。グローバルと一部の辞書は後のコードアクセス時に初期化されていることを保証するだけです。
もう一つはexec() を使う前に、他のより良い代替案があるかどうかを確認する必要があります。ほとんどの場合、 exec() を使用することを考慮すると、装飾器、クローズド、元、または他のいくつかの元のプログラミング特性などのより良い解決策があります。
以上がPythonのローカル変数領域でのコード実行の詳細です。Pythonのローカル変数領域に関する資料は他の関連記事に注目してください。