【python】関数内でexecによる代入を行ったときの、直観に反する動作について
1.環境
Python 3.8.2 (tags/v3.8.2:7b3ab59, Feb 25 2020, 23:03:10) [MSC v.1916 64 bit (AMD64)] on win32
2.実行したこと
>>> def f(arg):
... exec("a=arg")
... return a
...
>>> f(0)
3. 予想と現実
関数f
は引数arg
として受け取ったオブジェクトをそのまま返却するだろう。
なぜならば、exec("a=arg")
は関数f
内で実行されるから、f
内の変数a
には、引数arg
が代入されるはずだからだ。
4. 現実
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in f
NameError: name 'a' is not defined
変数a
は存在しないという旨のエラーが出た。
line 3 in f
にはreturn a
というコードが書かれているので、
exec
の実行時ではなく、return
の実行時にこのエラーは送出されたことといえる。
また、次のような再実験1を行ったことにより、return a
はf
内の変数ではなく、f
のひとつ外のスコープのa
を返却していたことが分かった。
>>> a = "外"
>>> def f(arg):
... exec("a=arg")
... return a
...
>>> f("内")
'外'
f
内で変数a
を呼んでいるにも関わらず、f
のひとつ外のスコープのa
が呼び出されているということは、
f
内のローカル変数a
が存在しないということを示唆している。すなわち、exec
は自身が呼ばれたスコープに対し、変数を代入することに失敗している。
このことは、再実験2により確かめることが出来た。
>>> a = '外'
>>> def f(arg):
... a = "内-非exec"
... exec("a=arg")
... return a
...
>>> f("内-exec")
'内-非exec'
5.質問
2章あるいは再実験1,2において、exec
は、どのスコープに対して変数a
を代入したのでしょうか。
また、以下に示す再実験3のように、exec
は、グローバルスコープで呼ばれる限り、自身が呼ばれたスコープに対して変数を代入することが可能ですが、なぜ関数内のローカルスコープでは同じことが可能ではないのでしょうか?
よろしくお願いいたします。
>>> a = "外-非exec"
>>> exec("a='外-exec'")
>>> a
'外-exec'