ValueError:尝试相对导入超出顶级包

nbr*_*bro 33 python-import python-3.x

我正在玩Python的导入系统,以便更好地理解它是如何工作的,我遇到了另一个问题.我有以下结构

pkg/
    __init__.py
    c.py
    d.py

    subpkg/
        __init__.py
        a.py
        b.py
Run Code Online (Sandbox Code Playgroud)

在里面a.py我有以下代码:

from . import b
from .. import d
Run Code Online (Sandbox Code Playgroud)

在里面c.py我有以下内容:

import subpkg.a
Run Code Online (Sandbox Code Playgroud)

现在我收到以下错误:

ValueError:尝试相对导入超出顶级包

为什么呢?我该如何解决?我c.py从IDLE 运行,pkg应该被认为是一个包,因为它有__init__.py文件.

第一个导入工作正常,但它是以下不起作用:

from .. import d
Run Code Online (Sandbox Code Playgroud)

因为我试图从父包中导入一些东西,但显然我不能,因为一些奇怪的原因.

typ*_*n04 37

这让我怀疑我的精神错乱。

问题源于人们错误地将相对导入视为路径相对而不是路径相对的混淆。

相对导入取决于运行的文件的位置。

这个答案更深入地解释了 python 模块的实际工作方式,但要总结一下。

  1. 加载文件时,会为其指定一个名称:
    • 如果它作为顶级脚本加载(直接运行),则其名称为__main__.
    • 如果它是作为模块加载的(带导入),它的名称是文件名,前面是它所属的任何包/子包的名称,用点分隔 -pkg.subpkg.a
  2. 如果你这样做from ..,文件名中必须至少有 2 个点。from ...- 3 点。

现在是有趣的部分。

如果您直接运行c.py,那么它会被赋予名称,__main__a.py具有subpkg.a.

根据第二条语句,您必须在名称中至少有 2 个点subpkg.a才能from ..在其中运行。

修复

pkg之外创建一个新文件,比如main.py

pkg/
    __init__.py
    c.py
    d.py

    subpkg/
        __init__.py
        a.py
        b.py
main.py
Run Code Online (Sandbox Code Playgroud)

在 main.py 里面

import pkg.c
Run Code Online (Sandbox Code Playgroud)

如果我们运行main.py,它会得到 name __main__,而a.py会得到pkg.subpkg.a. 根据第 2 条语句,它现在在名称中有 2 个点,我们可以执行from ..

还有一件事。现在c.py已作为模块加载,我们必须使用from加载a.py

from .subpkg import a
Run Code Online (Sandbox Code Playgroud)


JBe*_*rdo 5

Python 3 更改了导入系统,因此每次您想要一个与您正在工作的模块相邻的模块时,您都需要相对导入(除非您弄乱了PYTHONPATHsys.path)。

这里的正确用法应该是

from .subpkg import a
Run Code Online (Sandbox Code Playgroud)

当您使用 IDLE 时,您将拥有一个完全不同的环境。因此,您可以将当前位置添加到您的路径中,以便导入再次工作。

尝试:

sys.path.insert(0, '')
Run Code Online (Sandbox Code Playgroud)

这可能很奇怪,但这是为了更大的利益

PS:如果最后一件事不起作用——我现在没有空闲环境——可能是因为工作目录设置错误。

试试这个答案:https : //stackoverflow.com/a/17361545/754991

  • `from .subpkg import a` 没有回答这个问题。问题是问如何`from .. import d`。 (43认同)
  • 我已经对你所说的和 Python 的导入系统进行了一些了解,我想我更了解它是如何工作的。基本上,将文件作为“主”运行与作为由其他模块或“主”文件导入的模块或包之间存在区别。如果您只有一个运行整个应用程序的文件,您可以在子模块和子包之间进行相对导入。另一方面,正如您所说,相对导入在作为“main”运行的文件中不起作用。不幸的是,这是一个糟糕的限制...... (2认同)