使用任意变量作为 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
但我没想到这会起作用,因为我假设 fun
和 main
被解释为单独的代码片段,没有公共名称空间来解析 main
中的引用到fun
.
那么 main
的执行如何解析对 fun
的引用?
加法基于对问题的理解。对于 vals
和 globals
,id
的 print
,很明显这两个函数看到相同的全局变量:
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
的当前全局变量将用作全局变量(因此这仍然有效)。
使用此测试代码使用 exec
(使用 Python 3.4):
vals = {}
exec('def fun(): print("Hello from fun")', vals)
exec('def main(): fun()', vals)
vals['main']()
输出为:
Hello from fun
但我没想到这会起作用,因为我假设 fun
和 main
被解释为单独的代码片段,没有公共名称空间来解析 main
中的引用到fun
.
那么 main
的执行如何解析对 fun
的引用?
加法基于对问题的理解。对于 vals
和 globals
,id
的 print
,很明显这两个函数看到相同的全局变量:
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
的当前全局变量将用作全局变量(因此这仍然有效)。