__init__.py 文件并不会在项目启动时全部自动执行,它的执行遵循 Python 标准的包导入机制。
核心规则:只有被导入的包,其 __init__.py 才会执行
__init__.py 文件是 Python 中标识一个目录为"包(Package)"的标志。它的执行遵循两条核心规则:
- 触发条件 :只有当包含该
__init__.py文件的包(Package)被导入时,这个文件才会被执行。这里的"导入"包括直接导入该包,或导入该包下的任何子模块、子包。 - 执行次数 :每个包的
__init__.py文件在整个 Python 解释器会话期间,只会被执行一次 。首次导入后,模块会被缓存到sys.modules中。后续的导入操作会直接使用缓存,而不会重复执行。
FastAPI 项目中的具体表现
在 FastAPI 项目中,这个机制体现在应用的启动流程上:
- 启动入口 :当你使用
uvicorn main:app或类似命令启动应用时,Python 解释器会从入口文件(例如main.py)开始执行。 - 执行导入 :解释器会自上而下 执行
main.py中的代码。当遇到import语句时,便会去加载对应的模块或包。 - 触发执行 :这个加载过程会触发相关包的
__init__.py文件执行。例如:- 如果
main.py中有from .routers import user,那么routers包(即routers/__init__.py)会被执行。 - 如果
routers/__init__.py中又有from . import user, product,那么user.py和product.py模块在被导入时,其顶层代码也会被执行。
- 如果
因此,__init__.py 的执行是"按需"且"一次"的 。那些从未被任何代码导入的包,其 __init__.py 文件在整个应用生命周期中都不会被执行。
执行顺序与注意事项
- 顺序是深度优先 :当你导入一个深层模块如
import a.b.c时,Python 会依次执行a/__init__.py、a/b/__init__.py,最后才加载a/b/c.py。 - 避免在顶层执行重操作 :由于
__init__.py在导入时即执行,应避免在其中直接进行数据库连接、耗时计算等操作,以免阻塞应用启动。推荐将此类操作放在函数或 FastAPI 的lifespan事件中。 - 小心循环导入:多个模块相互导入容易导致循环依赖,从而引发错误。应合理设计代码结构来避免。
总结来说,__init__.py 的执行是 Python 导入机制的一部分,完全取决于代码中的 import 语句,而不是由 FastAPI 框架统一调度。