关于Python相对导入的解释
我实在搞不懂为什么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 个回答
在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
如果你打算直接调用 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]
指的是运行入口点时的路径。
你正在从“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
文件。