【问题标题】:Can anyone explain python's relative imports? [duplicate]谁能解释python的相对进口? [复制]
【发布时间】:2010-12-27 11:22:37
【问题描述】:

我一辈子都无法让 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。为什么会这样?如何使这个沙盒示例工作?

【问题讨论】:

标签: python


【解决方案1】:

在 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

如果我们在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

【讨论】:

    【解决方案2】:

    如果您要直接调用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】:

      您正在从包“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

      【讨论】:

      • 您混淆了“模块”和“包”这两个术语。 'start.py'代表模块'start','mod'和'mod.sub'是包,'mod'是顶级包。
      • 谢谢,但老实说,这似乎很愚蠢。对于这么漂亮的语言,我不敢相信设计师会创造出这样的限制。就没有别的办法了吗?
      • 一点也不傻。相对导入是指在包中引用兄弟模块的一种方式。如果要导入顶级模块,请使用绝对导入。
      • 不傻吗?所以在 bash 中,不能用“..”处理相对的上层目录不会打扰你吗?
      • 在我看来,python 的想法是从您启动父脚本的目录中使用“绝对”导入。因此,您可以使用绝对路径“import parent”从同级导入父模块。并且相对进口某种遗产或其他什么..
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多