我正在开发一个使用“运行时生成的模块”的应用程序。时尚如下:
import imp
import sys
a_module = imp.new_module("runtime_module")
sys.modules["runtime_module"] = a_module
对于简化的双功能示例,我将它们存储在两个不同的txt
文件中。我应该从文件中读取,但要使其更简单:
# First function
source_func1 = """def func1_implementation():
func2()
"""
# Second function
source_func2 = """def func2_implementation():
pass
"""
并且,要“填充”该类,我将代码加载到source_func1
和source_func2`并执行以下操作:
exec compile(source_func1, "__remote__func1__", "exec")
exec compile(source_func2, "__remote__func2__", "exec")
a_module.func1 = func1_implementation
a_module.func2 = func2_implementation
我希望能够做到以下几点:
import runtime_module
runtime_module.func1()
...然而
----------------------
NameError Traceback (most recent call last)
<ipython-input-11-4a304d14319a> in <module>()
1 import runtime_module
----> 2 runtime_module.func1()
/.../__remote__func1__ in func1_implementation()
NameError: global name 'func2' is not defined
如何管理命名空间?是否有一种pythonic方式来实现我想要做的事情?我对txt
文件(从中执行源文件)没有太多自由。我也不完全理解“where”是命名空间/ locals / globals,所以也许我忽略了一些简单的解决方案。
答案 0 :(得分:1)
你的主要问题是,当你执行一个函数定义时,它会将当时的全局环境绑定到它的__globals__
属性,并且当稍后调用该函数时,它是什么&#39; s用作框架的全局。
所以,你可以查看func1_implementation.__globals__
,它显然是你的模块的全局变量,而不是a_module
的全局变量。
您只需执行以下操作即可解决此问题:
exec compile(source_func1, "__remote__func1__", "exec") in a_module.__dict__
exec compile(source_func2, "__remote__func2__", "exec") in a_module.__dict__
a_module.func1 = a_module.func1_implementation
a_module.func2 = a_module.func2_implementation
最后两行替换setattr(…)
位,这只是混淆同样的事情。 a_module.func1 = <something>
与setattr(a_module, "func1", <something>)
相同,locals()["func1_implementation"]
与func1_implementation
相同。
请注意,这会将func1_implementation
放入a_module
。这并不像把它放到你自己的顶级模块那么糟糕,但它仍然不是很好。
您可以通过多种方式解决这个问题:只需提取code
个对象并使用types.FunctionType
构造绑定到正确命名空间的新function
对象,使用新的命名空间和填充在事实之后进入a_module
,或者,可能是最简单的,只是这个:
del a_module.func1_implementation
del a_module.func2_implementation
毕竟,这是你在普通模块中做的同样的事情,当你需要帮助函数来构建一个类或者什么东西但是不想在它构建之后在模块中保留它...