2

I created a simple package to illustrate this problem. Here's the file structure:

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

sub_a has a function foo:

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

sub_b has a function foobar that calls foo:

# sub_b/__init__.py
from sub_a import foo

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

In the main file, I import foobar without issues:

# __main__.py
from sub_b import foobar

if __name__ == '__main__':
    foobar()

If I run the package with python pypkg it works just fine. The problem starts when I try to use foobar from outside. I added pypkg to the path but when I try to import foobar it raises an ImportError exception. Here is a demo:

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

The ImportError happens not because it cannot find sub_b -- it can -- the problem happens because the package cannot import its own "neighbor subpackage". Which brings us to the question: How to properly import foobar from outside?

I made an extensive research on the topic and the vast majority of questions on SO are people that didn't place __init__.py files, observe this is not the issue here.

4

2 回答 2

2

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

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

sub_a并且sub_b将共享公共父模块pkg,即使从__main__.py. 这允许您在以下位置进行相对导入sub_b/__init__.py

from ..sub_a import foo

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

from __future__ import absolute_import
于 2017-05-09T13:12:50.503 回答
0

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

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

于 2017-05-09T13:01:32.903 回答