Python 从外部调用时,包无法导入邻居子包

Python package can't import neighbor subpackage when called from outside

我创建了一个简单的包来说明这个问题。这是文件结构:

pypkg
├── __init__.py
├── __main__.py
├── sub_a
│   └── __init__.py
└── sub_b
    └── __init__.py

sub_a 有一个函数 foo:

# sub_a/__init__.py
def foo():
    print 'foo'

sub_b 有一个函数 foobar 调用 foo:

# sub_b/__init__.py
from sub_a import foo

def foobar():
    foo()
    print 'bar'

在主文件中,我导入 foobar 没有问题:

# __main__.py
from sub_b import foobar

if __name__ == '__main__':
    foobar()

如果我 运行 带有 python pypkg 的包,它就可以正常工作。当我尝试从外部使用 foobar 时,问题就开始了。我在路径中添加了 pypkg,但是当我尝试导入 foobar 时,它引发了 ImportError 异常。这是一个演示:

In [1]: from pypkg.sub_b import foobar
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
<ipython-input-1-37682ecaec63> in <module>()
----> 1 from pypkg.sub_b import foobar

[...]/pypkg/sub_b/__init__.py in <module>()
----> 1 from sub_a import foo
      2 
      3 def foobar():
      4         foo()
      5         print 'bar'

ImportError: No module named sub_a

发生 ImportError 不是因为找不到 sub_b -- 它可以 -- 问题的发生是因为包无法导入它自己的 "neighbor subpackage"。这就引出了一个问题:如何从外部正确导入 foobar

我对该主题进行了广泛的研究,SO 上的绝大多数问题都是没有放置 __init__.py 文件的人,注意这不是这里的问题。

python根据你的工作路径计算路径。

因此您可以选择是使用固定工作路径的绝对模块路径还是使用可变工作路径的相对模块路径。

问题是 __main__.py 被视为脚本而不是 pypkg 模块的一部分。从 __main__.py 的角度来看,sub_asub_b 被视为不共享公共父模块的两个模块。如果您将布局更改为

pypkg
├── __main__.py
└── pkg
    ├── __init__.py
    ├── sub_a
    │   └── __init__.py
    └── sub_b
        └── __init__.py

sub_asub_b 将共享公共父模块 pkg,即使是从 __main__.py 调用时也是如此。这允许您在 sub_b/__init__.py:

中进行相对导入
from ..sub_a import foo

在 Python 2 下,您可能需要添加行

from __future__ import absolute_import