我有两个共享包名的独立项目。只要它们不在PYTHONPATH上,它们就会运行正常,但是一旦它们出现,其中一个就无法在自己的项目中找到导入。
示例,这样的两个项目:
项目1:
x/
__init__.py
test.py
foo.py
test.py包含以下行:
import x.foo
项目2:
x/
__init__.py
bar.py
如果我跑
PYTHONPATH=. python x/y/test.py
没有错误。但如果我跑
PYTHONPATH='pathtoproject2:.' python x/test.py
我收到错误:
Traceback (most recent call last):
File "x/test.py", line 1, in <module>
import x.foo
ImportError: No module named foo
有没有办法让不同的Python项目与一个共同的包共享PYTHONPATH?或者Python总是只使用找到包的第一个路径?
注意:我知道如果您修改从x.foo导入到导入foo,那么它将起作用。但是我想知道是否可以在不修改任何包的情况下进行。
答案 0 :(得分:3)
目前,Python不支持来自不同目录的包。包是一个单元,而不仅仅是一个命名空间。这与Java“包”或.NET中更恰当命名的“命名空间”不同。
导入包时,Python将按顺序扫描sys.path
,并使用第一个匹配项。如果路径中稍后出现的目录中有另一个具有匹配名称的模块或包,则无法找到它。
顺便说一下,你的“注意”是不正确的。当您使用import foo
时,Python将尝试在test.py
目录中进行相对导入,找不到匹配项,然后尝试绝对导入模块foo
,该模块也不存在,然后提出ImportError
。
不要使用包名称来使用公共前缀对模块进行分组,而应将包视为小型的自包含库。在Python中,flat is better than nested,并且最好有多个顶级包,每个包都有一个不同的目的,而不是拥有一个大的单片包。而不是org.example.foo
和org.example.bar
,只需使用foo
和bar
。
答案 1 :(得分:3)
虽然导入机制本身不支持,但有一种解决方法可以在python中创建命名空间包。您只需将以下代码放在__init__.py文件中。
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
pkg_resources 由setuptools python包提供,其优点是还可以处理egg zip文件中包含的包。
pkgutil 包含在python的标准库中,因此如果系统中未安装setuptools,我们依赖它来处理命名空间扩展。
有关python命名空间包的更多信息,请访问:
http://packages.python.org/distribute/setuptools.html#namespace-packages