Why do I get "NameError: name is not defined" with exec()?

Why do I get "NameError: name is not defined" with exec()?

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

In all cases, if the optional parts are omitted, the code is executed in the current scope.

由于上面的代码将 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()

... 也失败了,原因相同。

假设这就是您的真实代码中实际发生的事情,那么通过向 exec() 添加 globals(), globals() 参数来修改您的问题的版本会起作用,因为这样您就明确地导入了 random进入全局范围,一切都可以看到它。