Python 如何导入需要调整sys.path的命名空间包?
在我正在开发的python应用程序中,我希望根据运行时提供的信息(例如,从配置文件)动态加载包(插件) 因此,我更改sys.path以向我想要加载的插件添加路径,这通常可以正常工作,但如果插件是已初始化名称空间内的名称空间包,则不会这样做(我假设这就是问题所在) 例如:Python 如何导入需要调整sys.path的命名空间包?,python,python-2.6,import,Python,Python 2.6,Import,在我正在开发的python应用程序中,我希望根据运行时提供的信息(例如,从配置文件)动态加载包(插件) 因此,我更改sys.path以向我想要加载的插件添加路径,这通常可以正常工作,但如果插件是已初始化名称空间内的名称空间包,则不会这样做(我假设这就是问题所在) 例如: # lib1 contains plugins/__init__.py and plugins/foo/__init__.py # lib2 contains plugins/__init__.py and plugins/ba
# lib1 contains plugins/__init__.py and plugins/foo/__init__.py
# lib2 contains plugins/__init__.py and plugins/bar/__init__.py
# plugins is a namespace package
import sys
sys.path.append ('lib1')
import plugins.foo
sys.path.append ('lib2')
import plugins.bar
上面的代码以ImportError失败,可能是因为“import plugins.foo”行初始化了插件名称空间/包,并且没有进一步尝试在sys.path中搜索名称空间中的其他包
如果我将代码更改为:
sys.path.append ('lib1')
sys.path.append ('lib2')
import plugins.foo
import plugins.bar
两种导入都可以工作,但我想在plugins.foo导入之后添加到sys.path
因此,我的问题是:
我认为你的诊断是对的。导入
plugins.foo
时,python还会加载plugins
并将其缓存在sys.modules
中。我没有复制您的设置,但在导入bar
之前,我会尝试del sys.modules['plugins']
。如果不起作用,请尝试重新加载插件
:
sys.path.append ('lib2')
import plugins
reload(plugins)
import plugins.bar
我必须承认,一般认为,在运行程序时,重新加载不是一个好主意。“正确”的解决方案是制定一个工作流,允许您在开始从包导入之前设置完整的
sys.path
。或者不要把一个包裹分散在不同的地方。这不是答案,而是一个扩展的评论。
上述原始问题中给出的导入情况不仅仅出现在尝试导入两个不同插件时。在本例中,我们试图为当前系统中未安装所需Python包的情况提供本地回退
MVE的总体项目结构如下所示:
.
|-- src
| `-- balla
| |-- __init__.py
| `-- hurga
| `-- __init__.py
|-- src2
| `-- balla
| |-- __init__.py
| `-- hurga2
| `-- __init__.py
`-- test.py
,其中src/balla/_init__.py
和src2/balla/_init__.py
具有相同的源代码:
#!/usr/bin/env python
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
。两个src/balla/hurga/\uuuuu init\uuuuuu.py
和src2/balla/hurga2/\uuuuu init\uuuuu.py
现在是空的。在我们的主脚本test.py
中:
import sys, os
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'src'))
try:
import balla.hurga2
except:
sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'src2'))
import balla.hurga2
我们首先尝试直接从系统导入包“balla.hurga2
”,希望有人正确安装它(例如通过pip
)。第一个sys.path.append
与附加的src
文件夹相连接,尝试模拟安装了具有公共名称空间“balla”的其他软件包(例如balla.extended
)。但是balla.hurga2
不存在,因此名称空间“balla”的声明是成功的,但实际的导入不是。在除
之外的路径中,我们现在尝试通过将本地路径插入我们的回退包“src2
”来纠正这种情况。在新的import bala.hurga2
上,sys.modules
dict中的旧“balla”条目被缓存并保持不变。这将导致经典错误消息:
Traceback (most recent call last):
File "test.py", line 9, in <module>
import balla.hurga2
ImportError: No module named hurga2
如果系统中根本没有可用的
balla
包,则需要额外的if子句。您根本不需要修改sys.path。只需使用软件包。对于动态导入,您可以调用\uuuuuu导入
函数。或者使用imp
模块。如果我的操作正确,为什么不将plugins
制作成一个包,将plugins/lib1
和plugins/lib2
添加到路径中,然后import foo
和import bar
,我想你真正的问题是如何用Python制作一个插件系统——看看这个:我不熟悉重载,这解决了我的问题。谢谢
import sys, os
sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), 'src'))
try:
import balla.hurga2
except:
if 'balla' in sys.modules:
del sys.modules['balla']
sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'src2'))
import balla.hurga2