关于Python相对导入的解释

183 投票
3 回答
114891 浏览
提问于 2025-04-15 17:07

我实在搞不懂为什么Python的相对导入不管用。我做了个简单的例子,看看哪里出问题了:

文件夹结构是这样的:

__init__.py
start.py
parent.py
sub/
    __init__.py
    relative.py

/start.py 里面只有一句话:import sub.relative

/sub/relative.py 里面只有一句话:from .. import parent

其他文件都是空的。

当我在命令行执行以下命令时:

cd /
python start.py

我得到的结果是:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: Attempted relative import beyond toplevel package

我用的是Python 2.6。为什么会这样呢?我该怎么让这个简单的例子正常工作呢?

3 个回答

4

在Python 3中查看这个内容:

python -V
Python 3.6.5

示例1:

.
├── parent.py
├── start.py
└── sub
    └── relative.py

- start.py
import sub.relative

- parent.py
print('Hello from parent.py')

- sub/relative.py
from .. import parent

如果我们这样运行它(只是为了确保PYTHONPATH是空的):

PYTHONPATH='' python3 start.py

输出:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

如果我们在 sub/relative.py 中更改导入:

- sub/relative.py
import parent

如果我们这样运行它:

PYTHONPATH='' python3 start.py

输出:

Hello from parent.py

示例2:

.
├── parent.py
└── sub
    ├── relative.py
    └── start.py

- parent.py
print('Hello from parent.py')

- sub/relative.py
print('Hello from relative.py')

- sub/start.py
import relative
from .. import parent

这样运行:

PYTHONPATH='' python3 sub/start.py

输出:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 2, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

如果我们在 sub/start.py 中更改导入:

- sub/start.py
import relative
import parent

这样运行:

PYTHONPATH='' python3 sub/start.py

输出:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 3, in <module>
    import parent
ModuleNotFoundError: No module named 'parent'

这样运行:

PYTHONPATH='.' python3 sub/start.py

输出:

Hello from relative.py
Hello from parent.py

另外,最好从根文件夹导入,也就是:

- sub/start.py
import sub.relative
import parent

这样运行:

PYTHONPATH='.' python3 sub/start.py

输出:

Hello from relative.py
Hello from parent.py
35

如果你打算直接调用 relative.py,也就是说,如果你真的想从顶层模块导入东西,你需要明确地把它添加到 sys.path 列表中。
下面是应该怎么做的:

# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')

# Now you can do imports from one directory top cause it is in the sys.path
import parent

# And even like this:
from parent import Parent

如果你觉得上面的做法可能会导致某种不一致,你可以使用这个方法:

sys.path.append(sys.path[0] + "/..")

sys.path[0] 指的是运行入口点时的路径。

146

你正在从“sub”这个包中导入东西。虽然有一个 __init__.py 文件,但 start.py 本身并不在任何包里。

你需要从上一级目录开始运行你的程序,也就是 parent.py

./start.py

./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py

使用 start.py 的话:

import pkg.sub.relative

现在 pkg 就是顶层包,你的相对导入应该可以正常工作了。


如果你想保持现在的目录结构,可以直接使用 import parent。因为你是用 start.py 来启动你的解释器,所以 start.py 所在的目录会被加入到你的 Python 路径中。parent.py 就在那个目录里,作为一个独立的模块。

如果你在更上层的目录中没有导入任何东西,你也可以安全地删除顶层的 __init__.py 文件。

撰写回答