【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'