为什么我必须在包的 __init__.py 中使用相对导入?

Why do I have to use a relative import in a package's __init__.py?

设置

test/
    main.py
    pkg/
        a.py
        __init__.py

main.py 包含:

import pkg    
pkg.a

__init__.py 包含:

from . import a

main.py 可以 运行 没有错误。

问题

正在将 __init__.py 的内容更改为

import a

在运行ning main.py时出现如下错误:

Traceback (most recent call last):
  File "C:/Users/me/PycharmProjects/test/main.py", line 1, in <module>
    import pkg
  File "C:\Users\me\PycharmProjects\test\pkg\__init__.py", line 1, in <module>
    import a
ModuleNotFoundError: No module named 'a'

有意思的是,__init__.py可以直接用python __init__.py执行,不会出错

怎么回事?

当您 运行 一个 python 脚本时,它的父文件夹被添加到 sys.path

  • 运行 main.py: sys.path[0] = '../test'
  • 运行 初始化.py: sys.path[0] = '../test/pkg'

您的情况:您尝试在 __init__.py 中 "absolute-like" import aa.py 的父文件夹 - 即 '../test/pkg' - 不在sys.path 当你 运行 main.py。这就是您收到错误的原因。但是,您的绝对导入不完整,因为它应该始终从顶级文件夹开始,例如

from test.pkg import a

您问题的最终答案:您不必使用相对导入!

参见:PEP-8推荐使用绝对导入,因为如果导入系统不正确,它们通常更具可读性并且表现得更好(或至少给出更好的错误消息)配置(例如当包内的目录结束时 sys.path)。

请记住,当 __name__ = "__main__" 时,相对导入在顶级脚本中不起作用,但只能从导入的模块中运行。

您可以在此处了解有关绝对和相对导入的更多信息:
Absolute vs. explicit relative import of Python module
https://realpython.com/absolute-vs-relative-python-imports/

我想你正在使用 Pycharm?这就是造成混淆的原因之一。

例如,假设您的目录如下所示

project1
    p1.py
    test/
        __init__.py
        main.py
        pkg/
            a.py
            __init__.py

如果您 运行 (F10) main.py 您的默认工作目录将为 project1/test,其中不包含 a.py,因此 import a 将找不到任何东西。

但是如果你 运行 (F10) pkg/__init__.py 你的工作目录将是 project1/test/pkg 其中有 a.py,并且它像你测试的那样工作。

所以在这些情况下,如果您使用 from . import a,它将查找该文件所在的目录,在这种情况下 project1/test/pkg,无论您的工作目录如何,它都将始终有效。