46

次のコードでは、Python2と で異なる出力が得られPython3ます。

from sys import version

print(version)

def execute(a, st):
    b = 42
    exec("b = {}\nprint('b:', b)".format(st))
    print(b)
a = 1.
execute(a, "1.E6*a")

Python2プリント:

2.7.2 (default, Jun 12 2011, 15:08:59) [MSC v.1500 32 bit (Intel)]
('b:', 1000000.0)
1000000.0

Python3プリント:

3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
b: 1000000.0
42

関数内の変数を関数の文字列の値にPython2バインドするのに、これを行わないのはなぜですか? inの動作を実現するにはどうすればよいですか? で機能するグローバルとローカルの辞書を渡そうとしましたが、これまでのところ何も機能しませんでした。bexecuteexecPython3Python2Python3execPython3

- - 編集 - -

Martijns の回答を読んだ後、これをさらに分析しましたPython3。次の例では、locals()辞書をdに与えますexecd['b']、単に印刷する以外の何かを印刷しbます。

from sys import version

print(version)

def execute(a, st):
    b = 42
    d = locals()
    exec("b = {}\nprint('b:', b)".format(st), globals(), d)
    print(b)                     # This prints 42
    print(d['b'])                # This prints 1000000.0
    print(id(d) == id(locals())) # This prints True
a = 1.
execute(a, "1.E6*a")

3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)]
b: 1000000.0
42
1000000.0
True

dと の IDを比較すると、locals()それらが同じオブジェクトであることがわかります。しかし、これらの条件下bでは と同じである必要がありますd['b']。私の例では何が間違っていますか?

4

4 に答える 4

52

execPython 2 とPython 3 では大きな違いがあります。関数としてexec()扱っていますが、Python 2execでは実際にはステートメントです。

execこの違いにより、Python 2 では可能であったにもかかわらず、Python 3 では を使用して関数スコープ内のローカル変数を変更できません。以前に宣言された変数でさえありません。

locals()ローカル変数を一方向にのみ反映します。以下は、2 または 3 のいずれでも機能しませんでした。

def foo():
    a = 'spam'
    locals()['a'] = 'ham'
    print(a)              # prints 'spam'

Python 2 では、ステートメントを使用すると、コンパイラはローカル スコープの最適化をオフにすることを認識していました (たとえば、ローカル スコープとグローバル スコープの両方で変数を検索するためにからにexec切り替えます)。関数であるため、そのオプションは使用できなくなり、関数のスコープは常に最適化されます。LOAD_FASTLOAD_NAMEexec()

さらに、Python 2 では、execステートメントは で見つかったすべての変数locals()を を使用して関数 locals に明示的にコピーしますが、これはglobalsおよびlocalsパラメーターが指定されてPyFrame_LocalsToFastいない場合に限られます。

適切な回避策は、exec()呼び出しに新しい名前空間 (辞書) を使用することです。

def execute(a, st):
    namespace = {}
    exec("b = {}\nprint('b:', b)".format(st), namespace)
    print(namespace['b'])

exec()ドキュメントは、この制限について非常に明示的です。

注:デフォルトローカルは、以下の機能で説明されているように機能locals()します。デフォルト ローカル ディクショナリへの変更は試行しないでください。関数が戻った後にコードがローカルに与える影響を確認する必要がある場合は、明示的なローカル ディクショナリを渡しますexec()

于 2013-02-26T10:59:11.490 に答える
8

python3のバグだと思います。

def u():
    exec("a=2")
    print(locals()['a'])
u()

「2」を出力します。

def u():
    exec("a=2")
    a=2
    print(a)
u()

「2」を出力します。

しかし

def u():
    exec("a=2")
    print(locals()['a'])
    a=2
u()

で失敗します

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in u
KeyError: 'a'

--- 編集 --- 別の興味深い動作:

def u():
    a=1
    l=locals()
    exec("a=2")
    print(l)
u()
def u():
    a=1
    l=locals()
    exec("a=2")
    locals()
    print(l)
u()

出力

{'l': {...}, 'a': 2}
{'l': {...}, 'a': 1}

また、

def u():
    l=locals()
    exec("a=2")
    print(l)
    print(locals())
u()
def u():
    l=locals()
    exec("a=2")
    print(l)
    print(locals())
    a=1
u()

出力

{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}, 'a': 2}
{'l': {...}}

どうやら、ローカルに対するアクションはexec次のとおりです。

  • 内部に変数が設定されていてexec、この変数がローカル変数であった場合exec、内部辞書 ( によって返される辞書) が変更さlocals()れ、元の状態には戻されません。辞書を更新するための呼び出しlocals()(Python ドキュメントのセクション 2 に記載されているように) と、内部に設定された値execが忘れられます。辞書を更新するために呼び出す必要がlocals()あることは、文書化されているため、python3 のバグではありませんが、直感的ではありません。さらに、内部execのローカルの変更が関数のローカルを変更しないという事実は、python2 との文書化された違いです (ドキュメントには、「関数 exec() の後にローカルに対するコードの影響を確認する必要がある場合は、明示的なローカル ディクショナリを渡します。を返します)、私は python2 の動作を好みます。
  • 内部に変数が設定されていてexec、この変数が以前に存在しなかったexec場合、後で変数が設定されない限り、内部ディクショナリを変更します。locals()辞書を更新する方法にバグがあるようです。このバグにより、 afterexecを呼び出すことで内部で設定された値にアクセスできます。locals()exec
于 2015-05-19T21:50:56.403 に答える
1

残念ながら正確には説明できませんが、基本的には関数内の b がローカルでありexec()、グローバル b に代入されているように見えることに由来します。関数内およびexec ステートメント内でb をグローバルに宣言する必要があります。

これを試して:

from sys import version

print(version)

def execute1(a, st):
    b = 42
    exec("b = {}\nprint('b:', b)".format(st))
    print(b)

def execute2(a, st):
    global b
    b = 42
    exec("global b; b = {}\nprint('b:', b)".format(st))
    print(b)

a = 1.
execute1(a, "1.E6*a")
print()
execute2(a, "1.E6*a")
print()
b = 42
exec("b = {}\nprint('b:', b)".format('1.E6*a'))
print(b)

それは私に与えます

3.3.0 (default, Oct  5 2012, 11:34:49) 
[GCC 4.4.5]
b: 1000000.0
42

b: 1000000.0
1000000.0

b: 1000000.0
1000000.0

関数の外では、グローバル b が自動的に選択されていることがわかります。関数内で、ローカル b を出力しています。

exec()は常にグローバル b を最初に使用するためexecute2()、関数内で宣言する必要はないと考えていたことに注意してくださいexec()。しかし、それはうまくいかないことがわかりました(正確に説明できない部分です)。

于 2013-02-26T10:56:33.163 に答える