谁能解释python的相对导入?


174

我无法终生让python的相对导入工作。我创建了一个不起作用的简单示例:

目录结构为:

/__init__.py
/start.py
/parent.py
/sub/__init__.py
/sub/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。为什么会这样呢?如何使此沙盒示例正常工作?

Answers:


141

您正在从“ sub”包中导入。start.py即使有__init__.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如果您不将任何内容导入到目录树中更远的脚本中,也可以安全地删除顶层。


2
您会混淆术语“模块”和“包”。“ start.py”代表模块“ start”,“ mod”和“ mod.sub”是软件包,“ mod”是顶级软件包。
Ferdinand Beyer

36
谢谢,但是老实说这似乎很愚蠢。对于如此优美的语言,我无法相信设计师会创造出如此的限制。还有没有其他办法吗?
卡尔

2
一点都不傻。相对导入是指包中的同级模块的一种方式。如果要导入顶级模块,请使用绝对导入。
费迪南德·拜尔

61
不傻吗 因此,在bash中,无法使用“ ..”来解决相对较高的目录是否会困扰您?
e-satis

2
在我看来,python的想法是从启动父脚本的目录中使用“绝对”导入。因此,您可以使用绝对路径“导入父级”从同级导入父级模块。而相对进口某种传统的或任何..
奥德修斯

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] 指的是进入点运行的路径。


3

在python3中签出:

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

如果我们更改import in 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.