6

我有两个共享包名称的单独项目。只要它们不在 PYTHONPATH 上,它们就可以运行,但是一旦它们都出现,它们中的一个就无法在自己的项目中找到导入。

例如,两个这样的项目:

项目一:

x/
  __init__.py
  test.py
  foo.py

test.py 包含以下行:

import x.foo

项目二:

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 总是只使用找到包的第一个路径?

注意:我知道如果您将 import from x.foo 修改为 import foo 那么它将起作用。但我想知道是否可以在不修改任何一个包的情况下做到这一点。

4

2 回答 2

4

尽管导入机制本身不支持,但有一种解决方法可以在 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

http://www.python.org/dev/peps/pep-0382/

于 2012-01-27T23:31:46.847 回答
3

目前,Python 不支持来自不同目录的包。包是一个单元,而不仅仅是一个命名空间。这与 Java“包”或更恰当地命名为 .NET 中的“命名空间”不同。

导入包时,Python 将sys.path依次扫描并使用第一个匹配项。如果在路径后面出现的目录中存在具有匹配名称的另一个模块或包,则不会找到它。

顺便说一句,你的“笔记”不是真的。当您使用 时import foo,Python 会尝试在 的目录中进行相对导入test.py,找不到匹配项,然后尝试对foo也不存在的模块进行绝对导入,然后引发ImportError.

与其使用包名称来使用公共前缀对模块进行分组,不如将包视为较小的、自包含的库。在 Python 中,flat 优于 nested,并且最好拥有多个顶级包,每个包都实现一个不同的目的,而不是拥有一个大型的单体包。而不是org.example.fooand org.example.bar,只需使用fooand bar

于 2011-08-25T08:02:18.780 回答