Python sys.path模块解析的异常行为及相关疑问
Python导入同名命名空间包时为何不会遍历sys.path所有路径?
问题原因
Python的模块导入机制是一旦找到匹配的顶级包并加载后,后续导入操作会直接基于已加载的包对象,不会再遍历sys.path后续路径查找同名包。
具体到你的场景:
- 执行
import com.x.test2时,Python先扫描sys.path的第一个路径a,发现存在com包(因包含__init__.py),立即将com包对象加载到内存,绑定到a/com的路径。 - 接着尝试从已加载的
com包中查找x子包(找到a/com/x),再查找test2模块时发现不存在,直接抛出ImportError,不会再去b目录下的com包中尝试查找。
这是因为Python中包是单例对象,一旦com被导入(哪怕只是部分结构),后续的导入操作都会复用这个已加载的对象,不会重新去sys.path其他路径寻找同名包的其他部分。
解决方案:使用命名空间包
要让多个拥有同名命名空间的包协作,需要使用Python的命名空间包(Namespace Packages),具体分两种情况:
情况1:Python 3.3+(推荐)
直接删除所有com和x目录下的__init__.py文件,修改后的目录结构如下:
├── a │ └── com │ └── x │ └── test1.py └── b └── com └── x └── test2.py
此时Python会将a/com和b/com视为同一个命名空间包的不同部分,自动合并它们的子包和模块。执行以下命令都会成功:
python3 -c "import sys; sys.path = ['a', 'b']; import com.x.test1" python3 -c "import sys; sys.path = ['a', 'b']; import com.x.test2"
情况2:兼容Python 3.3之前版本
如果需要兼容旧版本Python,在每个com和x目录下添加__init__.py,内容如下:
from pkgutil import extend_path __path__ = extend_path(__path__, __name__)
这样也能实现多个同名命名空间包的路径合并,让不同目录下的com.x子包和模块可以被同时导入。
内容的提问来源于stack exchange,提问作者Alex Kyriazis
相关产品推荐
相关产品推荐

