为什么这个循环导入*将*在 python 中工作

why this circular import *will* work in python

我在我的代码中发现了一个奇怪的循环引用,这里是最小代码:

ph
|-- mod
|   |-- __init__.py
|   |-- pkg.py  # import mod.sub_mod.sub_pkg
|   `-- sub_mod
|       |-- __init__.py
|       `-- sub_pkg.py  # from mod import pkg
`-- main.py

mod中,只有pkg.pysub_pkg.py有文件内容。

main.py中:

import mod.pkg

会导致ImportError,但是

import mod.sub_mod.sub_pkg

效果不错。

当我试图找到这个最小的可重现示例时,我发现在 python 3 中,两个导入都可以工作。 我也找到了这个页面:https://gist.github.com/datagrok/40bf84d5870c41a77dc6 但我仍然不知道为什么。

如果您使用 import mod.pkg 开始循环导入,那么 mod/pkg.py 首先开始,然后尝试 import mod.sub_mod.sub_pkgmod/sub_mod/sub_pkg.py 启动,并尝试 运行 from mod import pkg,但是 mod.pkg 模块已经被初始化。

Python 跳到尝试从 mod 模块对象检索 pkg 属性。但是,直到 mod.pkg 模块完成初始化才设置该属性,因此 from mod import pkg 失败。


如果您使用 import mod.sub_mod.sub_pkg 启动循环导入,则 mod/sub_mod/sub_pkg.py 首先启动,然后尝试 运行 from mod import pkgmod/pkg.py 开始,并尝试 import mod.sub_mod.sub_pkgmod.sub_mod.sub_pkg 模块已经初始化,但是 Python 这次没有尝试访问属性。

from mod import pkg 需要从 mod 检索 pkg 属性,因为它需要将该属性的值绑定到本地命名空间中的名称 pkg。但是,import mod.sub_mod.sub_pkg 仅绑定本地名称空间中的 mod 名称。 Python 将 mod 名称绑定到 mod.pkg 模块命名空间中的 mod 模块并继续。


在Python 3中,在第一种情况下,当from mod import pkgmod上找不到pkg属性时,有一个回退。 Python 检查 sys.modules 字典中是否有 'mod.pkg' 的条目,找到一个,并将它找到的模块绑定到 pkg 名称。