首页 > 解决方案 > 从嵌入式 Python 脚本导入模块

问题描述

tl;dr 如何从嵌入式 Python 脚本中导入 Python 模块,以便导入的模块可以使用主机系统提供的全局变量和函数?

我正在为某个系统编写 Python 脚本(大概是用 C++ 编写的)。我编写脚本,将其放入一个特殊的预定义文件夹中,系统会在某些事件上执行它。

随着脚本变得庞大而笨拙,我想将其拆分为几个模块,比如说,module1.pymodule2.py,由 导入main_script.py,由主机系统加载和执行。但是,导入的模块不能使用全局的东西main_script.py(我假设,主机系统在加载时添加了一些全局变量、函数、类等main_script.py;但是,这些模块不是由主机系统直接加载的,所以它们最终不会拥有所有这些全局变量)。

到目前为止,我已经提出了以下内容 - 它查找存在于模块中main_script.py但不存在于模块中的全局变量,并将它们添加到模块中:

#main_script.py
import module1, module2

for m in [module1, module2]:
    for k, v in globals().items():
        if not hasattr(m, k):
            setattr(m, k, v)

它可以工作(至少对我来说到目前为止),但看起来并不特别优雅:我必须列出两次导入的模块;如果我想从模块中导入一些子模块,我必须在那里做同样的事情;我必须注意可能的全球名称冲突等)由于这个问题听起来并不少见,我觉得我可能在这里重新发明方轮。有一个更好的方法吗?

UPD.:根据@Merlin Katz 的回答和@Sraw 的评论[我的解释?] 建议,我修改了我的脚本如下。首先,添加了一个空脚本core.py。然后修改main_script.py

#main_script.py
import core
#only inject into the empty 'core' module
for k, v in globals().items():
    if not hasattr(core, k):
        setattr(core, k, v)

#can now import modules that depend on those globals
import module1, module2

然后,必须使用注入的全局变量的每个模块都应该core从那里导入并使用它们:

#module1.py
import core
_blah = core.blahblah #a shortcut

core.call_global_function()
my_obj1 = core.blahblah.SomeClassDefinedInBlahblah()
my_obj2 = _blah.SomeClassDefinedInBlahblah() #a bit shorter version of the above
#etc.

这看起来有点干净,并且没有覆盖某些现有全局变量的风险。由导入的模块,module1module2可以简单地import core使用全局变量。

UPD .:此外,我不确定它是否值得,但core.py您可以动态创建它,而不是保留一个空模块:

#main_script.py
import sys
from types import ModuleType
core = ModuleType("core")
sys.modules["core"] = core

#inject into our dynamically created 'core' module
for k, v in globals().items():
    if not hasattr(core, k):
        setattr(core, k, v)

#the modules can still import `core` the same way as before
import module1, module2

标签: pythonpython-embedding

解决方案


这应该可以解决必须列出两次模块的问题 - 您可以使用该importlib库从变量名中导入模块

>>> import importlib
>>> np = importlib.import_module('numpy')
>>> np.pi
3.141592653589793

所以从一个列表来看

import importlib
modules = [importlib.import_module(module_name) for module_name in module_names]
for m in modules:
    ...

至于同步全局变量,我不想这么说,但我认为没有完美的方法可以做到这一点。我之前遇到过这个问题,我的解决方案是将我希望在每个模块中可用的每个函数或变量放入一个单独的 core.py 文件中,每个模块都从该文件中导入。除此之外,我认为您拥有的是最简单的方法,如果有其他解决方案,我很想听听。


推荐阅读