Python 3.x ValueError:尝试在顶级包之外进行相对导入

Python 3.x ValueError:尝试在顶级包之外进行相对导入,python-3.x,python-import,Python 3.x,Python Import,为了更好地理解Python的导入系统是如何工作的,我在玩Python的导入系统时遇到了另一个问题。我有以下结构 pkg/ __init__.py c.py d.py subpkg/ __init__.py a.py b.py 在a.py内a.py我有以下代码: from . import b from .. import d 在c.py中,我有以下内容: import subpkg.a 现在我收到以下错误:

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

pkg/
    __init__.py
    c.py
    d.py

    subpkg/
        __init__.py
        a.py
        b.py
在a.py内
a.py
我有以下代码:

from . import b
from .. import d
c.py
中,我有以下内容:

import subpkg.a
现在我收到以下错误:

ValueError:尝试在顶级包之外进行相对导入

但是为什么呢?我怎样才能解决它?我正在空闲状态下运行
c.py
,而
pkg
应该被视为一个包,因为它有
\uuuuu init\uuuuuuu.py
文件

第一次导入工作正常,但以下内容不起作用:

from .. import d

因为我正试图从父包导入一些东西,但由于某些奇怪的原因,显然我无法导入。

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

这里的正确用法应该是

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

尝试:

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

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


试试这个答案:

这让我怀疑我的精神错乱

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

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

本文将更深入地解释python模块实际上是如何工作的,但仅作总结

  • 加载文件时,会为其指定一个名称:
    • 如果它作为顶级脚本加载(直接运行),则其名称为
      \uuuuu main\uuuu
    • 如果它是作为模块加载的(带有导入),则其名称为文件名,前面是它所属的任何包/子包的名称,以点分隔-
      pkg.subpkg.a
  • 如果从..执行
    ,文件名中必须至少有2个点<代码>来自…
    -3点
  • 现在是有趣的部分。

    如果直接运行c.py,那么它将被命名为
    \uuu main\uu
    ,而a.py具有
    子kg.a

    根据第2条语句,您必须在
    subkg.a
    名称中至少有2个点才能从..中运行

    修复程序

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

    pkg/
        __init__.py
        c.py
        d.py
    
        subpkg/
            __init__.py
            a.py
            b.py
    main.py
    
    内main.py

    import pkg.c
    
    如果我们运行main.py,它的名称是
    \uuu main\uuu
    ,而a.py get的名称是
    pkg.subpkg.a
    。根据第2条语句,它的名称中现在有2个点,我们可以从..

    还有一件事。既然c.py是作为模块加载的,那么我们必须使用from来加载a.py

    我找到了这个解决方案:

    #/usr/bin/env python
    导入操作系统
    导入系统
    sys.path.append(os.path.realpath('.'))
    从d进口*
    
    我很感谢上面的答案,但我觉得建议的解决方案有点不令人满意。我的建议是:只需将sys.path.append(“.”)添加到主文件中。这允许导入第一级包,而无需对项目架构进行任何更改。放下前一个。。不再需要了。

    只需在所有文件夹中添加/创建init.py文件即可解决问题

    折叠1 -折叠2 -file1.py -折页3 -折页4 -file2.py

    我想在file2.py中使用file1.py中的一个方法[基本上是向上两级]。 因此,我在上面的所有文件夹和子文件夹中添加了空的init.py,并在下面的file2.py中使用:-


    从folder2.file1导入

    如果我从.subpkg导入a接收:
    系统错误:未加载父模块“”,无法从空闲模块和终端执行相对导入
    。@nbro这是因为您在空闲模块内,但当您在模块内运行时,导入应该是这样的。IDLE是一个糟糕的IDE,对python开发总体上是不利的。在空闲模块和内部模块上最有效的选项是使用完整的包名:
    from pkg import subpkg.a
    sys.path
    上添加
    pkg
    的目录后,“在模块内运行它”是什么意思?我说过,我按照您的建议从终端和空闲运行文件
    c.py
    (作为main),它给出了我上面提到的错误。IDLE是一个糟糕的IDE,但它是Python自带的吗?携带一个可怕的IDE的目的是什么?你可以说IDLE是一个过于简单的IDE,当然它不是最好的IDE之一,但理论上它应该可以很好地与Python配合使用,否则就没有什么意义了。我已经对你所说的内容和Python的导入系统做了一些介绍,我想我对它的工作原理有了更多的了解。基本上,作为“主”文件运行的文件与作为其他模块或“主”文件导入的模块或包运行的文件是有区别的。如果只有一个文件运行整个应用程序,则可以在子模块和子包之间进行相对导入。另一方面,正如您所说,相对导入在作为“main”运行的文件中不起作用。不幸的是,这是一个错误的限制…
    from.import a
    无法回答问题。问题是如何从。。导入d。
    import pkg.c
    
    from .subpkg import a