2

この答えを研究する中で、私は驚いたことに、それ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'

明らかに、どちらも何らかのグローバル値を返しますxf2()が少し変更された場合はそうではありません:

>>> 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 でも同じように機能します)

4

1 に答える 1