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

在我正在开发的python应用程序中,我希望根据运行时提供的信息(例如,从配置文件)动态加载包(插件)

因此,我更改sys.path以向我想要加载的插件添加路径,这通常可以正常工作,但如果插件是已初始化名称空间内的名称空间包,则不会这样做(我假设这就是问题所在)

例如:

# 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