为什么下面的代码在崩溃后仍能工作?
我不知道如何用英语表达我的问题,所以我附上了我能想到的最小的代码来强调我的问题。
(上下文:我正试图为python创建一个终端环境,但是由于某种原因,名称空间似乎被弄乱了,下面的代码似乎是我的问题的本质)
无错误:
d={}
exec('def a():b',d)
exec('b=None',d)
exec('a()',d)
错误:
d={}
exec('def a():b',d)
d=d.copy()
exec('b=None',d)
d=d.copy()
exec('a()',d)
最佳答案
这是因为d
不使用exec
提供的全局变量;它使用它在第一个exec
中存储引用的映射。在新字典中设置'b'
时,从未在该函数的全局中设置b
。
>>> d={}
>>> exec('def a():b',d)
>>> exec('b=None',d)
>>> d['a'].__globals__ is d
True
>>> 'b' in d['a'].__globals__
True
对
>>> d={}
>>> exec('def a():b',d)
>>> d = d.copy()
>>> exec('b=None',d)
>>> d['a'].__globals__ is d
False
>>> 'b' in d['a'].__globals__
False
如果
exec
不能这样工作,那么这也会失败:模型py
b = None
def d():
b
主.py
from mod import d
d()
函数将记住它最初创建的环境。
无法更改现有函数指向的字典。您可以显式地修改它的全局参数,也可以使另一个函数对象完全相同:
from types import FunctionType
def rebind_globals(func, new_globals):
f = FunctionType(
code=func.__code__,
globals=new_globals,
name=func.__name__,
argdefs=func.__defaults__,
closure=func.__closure__
)
f.__kwdefaults__ = func.__kwdefaults__
return f
def foo(a, b=1, *, c=2):
print(a, b, c, d)
# add __builtins__ so that `print` is found...
new_globals = {'d': 3, '__builtins__': __builtins__}
new_foo = rebind_globals(foo, new_globals)
new_foo(a=0)