1

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

但我不明白为什么。

这是怎么回事?

4

1 回答 1

1

你在你的程序中没有做“完全相同”。确切的代码,逐字复制到文件中并作为 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您的问题中提到的异常,因为(引用文档),

在所有情况下,如果省略了可选部分,则代码将在当前范围内执行。

由于上面的代码导入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到全局范围中,所有内容都可以看到它。

于 2019-02-24T11:59:06.303 回答