当我在控制台(在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/

10-10 17:37