谁能解释python的相对导入?

问题:谁能解释python的相对导入?

我无法终生让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。为什么会这样呢?如何使此沙盒示例正常工作?

I can’t for the life of me get python’s relative imports to work. I have created a simple example of where it does not function:

The directory structure is:

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

/start.py contains just: import sub.relative

/sub/relative.py contains just from .. import parent

All other files are blank.

When executing the following on the command line:

$ cd /
$ python start.py

I get:

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

I am using Python 2.6. Why is this the case? How do I make this sandbox example work?


回答 0

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

You are importing from package “sub”. start.py is not itself in a package even if there is a __init__.py present.

You would need to start your program from one directory over parent.py:

./start.py

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

With start.py:

import pkg.sub.relative

Now pkg is the top level package and your relative import should work.


If you want to stick with your current layout you can just use import parent. Because you use start.py to launch your interpreter, the directory where start.py is located is in your python path. parent.py lives there as a separate module.

You can also safely delete the top level __init__.py, if you don’t import anything into a script further up the directory tree.


回答 1

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

If you are going to call relative.py directly and i.e. if you really want to import from a top level module you have to explicitly add it to the sys.path list.
Here is how it should work:

# 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

If you think the above can cause some kind of inconsistency you can use this instead:

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

sys.path[0] refers to the path that the entry point was ran from.


回答 2

在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

Checking it out in python3:

python -V
Python 3.6.5

Example1:

.
├── 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

If we run it like this(just to make sure PYTHONPATH is empty):

PYTHONPATH='' python3 start.py

Output:

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

If we change import in sub/relative.py

- sub/relative.py
import parent

If we run it like this:

PYTHONPATH='' python3 start.py

Output:

Hello from parent.py

Example2:

.
├── 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

Run it like:

PYTHONPATH='' python3 sub/start.py

Output:

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

If we change import in sub/start.py:

- sub/start.py
import relative
import parent

Run it like:

PYTHONPATH='' python3 sub/start.py

Output:

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

Run it like:

PYTHONPATH='.' python3 sub/start.py

Output:

Hello from relative.py
Hello from parent.py

Also it’s better to use import from root folder, i.e.:

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

Run it like:

PYTHONPATH='.' python3 sub/start.py

Output:

Hello from relative.py
Hello from parent.py