この答えを研究する中で、私は驚いたことに、それexecが奇妙な振る舞いをしていることを発見しました。
>>> def f1():
... return x
...
>>> def f2():
... exec ""
... return x
...
>>> f1()
Traceback (most recent call last):
...
NameError: global name 'x' is not defined
>>> f2()
Traceback (most recent call last):
...
NameError: name 'x' is not defined
>>> x = 'bar'
>>> f1()
'bar'
>>> f2()
'bar'
明らかに、どちらも何らかのグローバル値を返しますx。f2()が少し変更された場合はそうではありません:
>>> def f2():
... exec "x = 'im local now'"
... return x
...
>>> f2()
'im local now'
xf2の本体にはそれを引き起こすと思われるものは何もありませんが (x への代入はありません)、f2 は の独自の特別なコピーを返します。
これがどのように起こっているかを簡単に見ることができます. の存在が関数をジェネレータに変えるのと同様に、execステートメントの存在はLOAD_GLOBALバイトコードを に変更します.LOAD_NAMEyield
>>> dis.dis(f1)
2 0 LOAD_GLOBAL 0 (x)
3 RETURN_VALUE
>>> dis.dis(f2)
2 0 LOAD_CONST 1 ('')
3 LOAD_CONST 0 (None)
6 DUP_TOP
7 EXEC_STMT
3 8 LOAD_NAME 0 (x)
11 RETURN_VALUE
しかし、私が理解していないのはその理由です。これは文書化された動作ですか? これは cpython の実装の詳細ですか? dis(モジュールは機能しませんが、IronPython でも同じように機能します)