これで 3 が出力されると思ったのですが、1 が出力されます。
def f():
a = 1
exec("a = 3")
print(a)
これで 3 が出力されると思ったのですが、1 が出力されます。
def f():
a = 1
exec("a = 3")
print(a)
この問題はPython3 バグ リストでいくらか議論されています。最終的に、この動作を得るには、次のことを行う必要があります。
def foo():
ldict = {}
exec("a=3",globals(),ldict)
a = ldict['a']
print(a)
で Python3 のドキュメントexec
を確認すると、次の注記が表示されます。
locals()
デフォルトのローカルは、以下の機能で説明されているように機能します。デフォルトのローカル ディクショナリへの変更は試行しないでください。関数 exec() が戻った後にローカルに対するコードの影響を確認する必要がある場合は、明示的なローカル ディクショナリを渡します。
つまりexec
、変数の代入、インポート、関数定義、クラス定義など、ローカル変数をバインドする操作を 1 つの引数で安全に実行することはできませんglobal
。宣言を使用する場合はグローバルに代入できますが、ローカルには代入できません。
バグ レポートの特定のメッセージを参照して、Georg Brandl は次のように述べています。
その場で関数のローカルを変更することは、いくつかの結果なしには不可能です:通常、関数のローカルは辞書には格納されませんが、配列に格納され、そのインデックスは既知のロケールからコンパイル時に決定されます。これは、少なくとも exec によって追加された新しいローカルと衝突します。古い exec ステートメントはこれを回避していました。コンパイラは、グローバル/ローカル引数のない exec が関数で発生した場合、その名前空間が「最適化されていない」、つまり locals 配列を使用しないことを知っていたからです。exec() は現在、通常の関数であるため、コンパイラは "exec" が何にバインドされている可能性があるかを認識していないため、 is を特別に扱うことができません。
強調は私です。
したがって、その要点は、デフォルトでこの動作を許可しないことで、Python3 がローカル変数の使用をより最適化できるということです。
上記のコメントで述べたように、完全を期すために、これはPython 2.X で期待どおりに機能します。
Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def f():
... a = 1
... exec "a=3"
... print a
...
>>> f()
3
メソッド内にいる場合は、次のように実行できます。
class Thing():
def __init__(self):
exec('self.foo = 2')
x = Thing()
print(x.foo)