当我在控制台(在PyCharm中)中尝试此代码时:
exec("import random")
exec("def f():\n\treturn random.randint(0, 10), random.randint(0, 10)")
locals()['f']()
它工作正常。但是,当我尝试在程序中执行完全相同的操作时,它不起作用,并且出现异常
NameError: name 'random' is not defined.
我发现这段代码不会引发错误:
exec("import random", globals(), globals())
exec("def f():\n\treturn random.randint(0, 10), random.randint(0, 10)", globals(), globals())
globals()['f']()
但是我不明白为什么。
这是怎么回事?
最佳答案
您不会在程序中执行“完全相同”的操作。将该精确的代码逐字复制到文件中并作为Python脚本运行,可以正常工作(尽管没有可见结果)。
我认为您可能实际上正在做的事情是这样的:
def import_stuff():
exec("import random")
def do_stuff():
import_stuff()
exec("def f():\n\treturn random.randint(0, 10), random.randint(0, 10)")
locals()['f']()
do_stuff()
上面的代码确实会导致您的问题中提到的
NameError
异常,因为(引用docs),在所有情况下,如果省略了可选部分,则代码将在当前范围内执行。
由于上面的代码将
random
导入到import_stuff()
的本地范围中,因此do_stuff()
不可见。实际上,上面的代码在行为上与以下代码相同:
def import_stuff():
import random
def do_stuff():
import_stuff()
def f():
return random.randint(0, 10), random.randint(0, 10)
f()
do_stuff()
……由于同样的原因,它也失败了。
假设这是实际代码中真正发生的事情,那么通过在
globals(), globals()
中添加exec()
自变量来修改问题的版本将是可行的,因为这样您便可以将random
明确导入全局范围,在此范围内,所有内容都可以看见。关于python - 为什么通过exec()会收到“NameError:名称未定义”?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54840271/