首页 > 解决方案 > 为什么 Python 导入会隐式执行父模块?

问题描述

正如Python 文档所述,模块导入(以及从模块导入)总是在执行可能的父模块。例如,这些构成常规包的文件:

a_package/
  __init__.py
  a_submodule.py

a_submodule从完全不同的包中导入,例如

from a_package.a_submodule import an_object

将首先执行a_package/__init__.py,然后再执行a_package/a_submodule.py并最终绑定an_object到声明导入的命名空间。

我想知道这背后的设计原理或技术必要性是什么。特别是因为这对我来说似乎违反直觉,因为通常的包机制是一个有序图,其中父模块取决于其子包中的内容,反之亦然。事实上,如果该 import 语句示例在 中进行了评估a_package/__init__.py,它不会触发自身的执行。当然,因为这将是一个循环依赖,但它表明子模块不依赖于它们的父模块。

标签: pythonpython-3.xpython-module

解决方案


有几个原因。从能力的角度来看,最重要的是,包可以使用诸如__path__帮助查找其子模块之类的机制,如果在继续导入子模块之前未对其进行配置,这显然将不起作用。另一个是方便:如果一个包在使用它的模块之前需要初始化,它可以被放入__init__.py而不是让每个模块都需要from . import startup

此外,应该在什么时候初始化包?等到所有子模块都被导入是没有意义的,因为这可能永远不会发生;虽然它可能是“在子模块的第一次导入完成之后”,但仍然是在其他子模块的导入之前,并且会不一致和任意。特别是,没有模块可以使用其父级的内容,__init__.py以防它是其兄弟姐妹中第一个被导入的。

至于循环依赖,Python 一直支持这些(至少对于绝对导入):导入一个已经被导入的模块只会产生一个对模块对象的引用(处于其部分形成的状态)。的行为from . import foo(顺便说一句,作为执行的一部分通常是一个坏主意__init__.py)也不例外。由于“额外导入”只是sys.modules无论如何,它根本没有效果。


推荐阅读