使用任意变量作为 exec 的命名空间

Using arbitrary variables as namespaces for `exec`

使用此测试代码使用 exec(使用 Python 3.4):

vals = {}
exec('def fun(): print("Hello from fun")', vals)
exec('def main(): fun()', vals)
vals['main']()

输出为:

Hello from fun

但我没想到这会起作用,因为我假设 funmain 被解释为单独的代码片段,没有公共名称空间来解析 main 中的引用到fun.

那么 main 的执行如何解析对 fun 的引用?


加法基于对问题的理解。对于 valsglobalsidprint,很明显这两个函数看到相同的全局变量:

vals = {}
print('id(vals):', id(vals))
exec('def fun(): print("fun id(globals()):", id(globals())); print("Hello from fun")', vals)
exec('def main(): print("main id(globals()):", id(globals())); fun()', vals)
vals['main']()

给出:

id(vals): 32271016

main id(globals()): 32271016

fun id(globals()): 32271016

Hello from fun

因此 vals 被用作 exec 中代码的全局变量,从而给出连接,如@Dunes 和其他评论所述。谢谢。

通过为两个 exec 函数提供 vals,您已经提供了公共命名空间。 exec 的第二个参数是一个字典,用于在任何执行的代码中进行全局引用。当执行第一条语句时,它创建 fun 并将其存储在全局命名空间 (vals) 中。因此,当 main 尝试查找 fun 时,它发现它不是局部变量,因此尝试在其全局变量(也是 vals)中查找 fun .由于 fun 存在于 vals 中,因此查找有效,并且检索和调用了函数。如果给每个 exec 它自己的 dict 那么这将不起作用。如果您不提供 vals,则调用 exec 的当前全局变量将用作全局变量(因此这仍然有效)。