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



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

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 - 它可以 - 问题发生是因为包无法导入自己的"邻居子包"。这就引出了一个问题:如何正确地从外部导入foobar

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

问题是__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

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

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

相关内容

  • 没有找到相关文章

最新更新