45

これで 3 が出力されると思ったのですが、1 が出力されます。

def f():
    a = 1
    exec("a = 3")
    print(a)
4

3 に答える 3

65

この問題は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
于 2009-09-23T00:37:27.167 に答える
4

メソッド内にいる場合は、次のように実行できます。

class Thing():
    def __init__(self):
        exec('self.foo = 2')

x = Thing()
print(x.foo)

詳細については、こちらをご覧ください。

于 2015-09-28T17:32:06.517 に答える