出人意料的智能 python 导入行为:幕后发生了什么?

Surprisingly smart python import behaviour : what's happening under the hood?

Python 导入是 confusing,但我以为我终于理解了它们,直到我偶然发现了这种行为(在 3.9.1 中)。这里发生了什么?

采用这个包结构:

countries/
├── __init__.py  # from . import greece
├── greece.py
└── spain.py

如果我这样做 import countries,命名空间 dir(countries) 只包含 greece,正如预期的那样。

但是如果我开始我的会话:

from countries import spain
import countries

命名空间 dir(countries) 包含 greecespain !

我在第一次导入时知道 __init__.py 是 运行。我不明白的是 python 是如何记住在 countries 命名空间中包含 greecespain 的。它是否在 运行ning from countries import spain 之后将 countries 命名空间保存在引擎盖下的某个地方,然后 运行ning import countries 只是将它添加到本地命名空间?

你是对的。导入模块时 python 将其保存在导入模块列表中。当您 from countries import spain 然后导入根时,python 知道 spain 是父模块 countries 的子模块。所以当你 import countries 它只是将你不需要的子模块添加到父模块中。

请参阅此处了解实际逻辑:https://github.com/python/cpython/blob/f32c7950e0077b6d9a8e217c2796fc582f18ca08/Lib/importlib/_bootstrap.py#L1007