この答えを研究する中で、私は驚いたことに、それ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'
x
f2の本体にはそれを引き起こすと思われるものは何もありませんが (x への代入はありません)、f2 は の独自の特別なコピーを返します。
これがどのように起こっているかを簡単に見ることができます. の存在が関数をジェネレータに変えるのと同様に、exec
ステートメントの存在はLOAD_GLOBAL
バイトコードを に変更します.LOAD_NAME
yield
>>> 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 でも同じように機能します)