当前位置: 首页 > 知识库问答 >
问题:

无法使导入与子包一起工作

顾琛
2023-03-14

以下结构(在Python3.7中)不允许我在模块B中导入类A

package:
    package:
        __init__.py
        a:
            __init__.py
            a.py
        b:
            __init__.py
            b.py

顶层的\uuuu init\uuuu。py为空。以下是剩余的文件:

a

# package/package/a/__init__.py

from .a import A
# package/package/a/a.py

class A:

    def __init__(self):
        pass

b:

# package/package/b/__init__.py

from .b import B
# package/package/b/b.py

from package.a.a import A

class B:

    def __init__(self):
        pass

在Windows上,如果我尝试运行b.py(从b文件夹中)而不做任何其他操作,我会得到以下错误:

ModuleNotFoundError: No module named 'package.a'

如果我在顶层添加一个main.py

package:
    package:
        __init__.py
        main.py
        a:
            __init__.py
            a.py
        b:
            __init__.py
            b.py

包含

# package/package/main.py

import a
import b

并运行main.py(从包/包内),我得到同样的错误。

如果我将b.py更改为

# package/package/b/b.py

from ..a.a import A

class B:

    def __init__(self):
        pass

然后运行b.py(从b文件夹中)或main。py(从package/package)中,我得到了

ValueError: attempted relative import beyond top-level package

python文档让我觉得我应该能够做到这一点!

有人能解释一下我为什么会犯这些错误吗?我看到过几篇类似的帖子,但它们并没有解决我的问题:

  1. 导入子模块Python 3

共有1个答案

申屠宗清
2023-03-14

Python运行的任何模块都称为顶级。

  • 在shell中,当您运行

不幸的是(IMO),术语“顶层”在python文档中没有很好的定义,因为它在几个不同的上下文中使用。无论如何,重要的是要理解Python总是将顶级实体的\uuuuu name\uuuu重命名为“\uuuuu main\uuuu”

PEP 328(在本SO帖子中解释)指出

相对导入使用模块的___属性来确定其在包层次结构中的位置。

由于Python将顶层模块的\uuuu name___重命名为“\u_main____,顶层模块没有包信息,因为它的名称中没有点。

因此,顶级模块不被视为任何包的一部分(尽管它们很可能是!)。换句话说,对于从当前目录导入的包,“\uuuuu main\uuuu”确定什么是顶级的。与“main”处于同一级别的包(在我的示例中是ab)是顶级包。

令人困惑的是,python文档和PEP 328给出了一个误导性的例子。为相对导入显示的“正确用法”仅在特定上下文中有效。

回想一下,import搜索sys中列出的路径。路径查找要导入的包和模块。当前目录位于sys中。路径,以及指向内置软件包(如mathos)和已安装软件包(即pip安装ed软件包)的路径。Python不会重命名非顶级软件包的___

因此,python文档和PEP 328示例仅对不在顶级目录中的包和模块有效。

我应该写的是from a. a import A

# package/package/b/b.py

from a.a import A

class B:

    def __init__(self):
        pass

由于pack位于顶级模块之上,因此尝试进行绝对导入(例如from pack. a. a import a)会导致重要错误即使main.py在包内部。

也就是说,如果你去PyPI和GitHub看看发布的包,你会发现它们有绝对的导入,比如import-package。a、 a!事实上,如果我发布我的包,并将导入作为a.a导入a,最终用户将获得一个ImportError,因为他们安装了包package,而没有包a!此外,在当前配置中,我无法使用unittestpytest测试用户可以按预期导入和使用我的包,因为我无法从包中执行。a、 a导入a我自己!

所以问题变成了如何编写和测试自己的定制包?

诀窍是这些包是在开发模式下编写的。要在开发模式下安装您的包,请运行

完成此操作后,python会将您的包视为典型的库包(即pip installed包),因此python不会将其__name__更改为__main__。因此,您可以

  • 以绝对进口量进口

开发软件包和独立程序之间的这一关键区别对于大多数初次开发人员(包括我自己)来说都是一个巨大的困惑和挫败源,需要记住这一点非常重要。我希望这个答案能为其他人提供澄清,并在将来添加到文档中。如果这对你有帮助,请在下面的评论中告诉我。

注意:pip安装-e,其中-e代表“可编辑”,将一个链接(a*.pth文件)放在python安装文件夹中,这样该包就被视为已安装的包,但您在其中编写的任何更改都将立即生效(请参阅python打包教程)。因此,您可以使用它来开发自己的软件包,或者根据需要安装和编辑第三方软件包。这需要创建设置。py,但您的所有测试代码、客户端代码等都将能够以通常的方式导入您的包(即,您可以像对待任何其他pip安装ed包一样对待您的包)。通过配置pyproject,您可以使用poetryflit实现相同的效果。toml文件。

以下是一些其他有用的参考资料:

  1. 真蟒蛇。com:Python模块和包-简介
  2. 真蟒蛇。com:Python导入:高级技术和技巧
  3. 真蟒蛇。com:Python中的绝对导入与相对导入

 类似资料:
  • 问题内容: 我想知道为什么没有确定的合作方式。我只想解析字符串: 但是我真的很困惑应该导入什么。根据此链接,我尝试导入。但是我得到这个编译错误: 然后我尝试导入和。因此,没有编译错误,但是我得到了此运行时异常(在mapper定义行中): 请指导我,我应该导入什么才能使用。谢谢 问题答案: 使用这些依赖项 jackson-databind jackson-annotations jackson- c

  • 我对scrollview和GeometryReader有一些问题。我想要一张图片下的物品清单。每个项目都应该有以下宽度和高度: 我为我的用例尝试了两种方法。这是我的第一个代码结构: 我正在使用几何体读取器来获取VStack的宽度,因为它有一个填充,我不想获得滚动视图的全宽。 但对于GeometryReader,UI上只显示ForEach循环中的最后一项。而GeometryReader只有很小的高度

  • 我在使用pymongo进行mongodb聚合时遇到了< code >聚合结果超过最大文档大小(16MB)错误。 起初,我使用< code>limit()选项克服了这个问题。然而,在某个时候,我得到了 好的,我将使用 选项。当我在命令行上使用它时,此选项有效,但是当我尝试在我的 python 代码中使用时,此选项有效 我得到< code>TypeError: aggregate()正好接受2个参数(

  • 我正在尝试为模板制作一个包含node、express和ejs的简单服务器。我已经让服务器指向页面,加载它,甚至能够用include语句生成其他代码。但是,由于某种原因,样式表将不会加载。 应用程序JS ejs文件位于views/board.ejs目录中 并且style.css位于与app.js相对的styles/style.css目录中 对于链接的href,我尝试了所有我能想到的路径,包括相对于我

  • 问题内容: 在我编写的flask应用程序中,我使用了一个外部库,该库可以使用环境变量进行配置。注意:我自己编写了这个外部库。因此,如有必要,我可以进行更改。从命令行运行时,运行带有以下内容的烧瓶服务器: 一切都如预期。但将它部署到Apache后,用它不工作了。事实上,打印出到(所以它在Apache日志中显示出来显示,该wsgi过程似乎是在一个非常不同的环境(一个,好像是这样了。其实,它指向我的发展