__init__.py文件的核心作用是标识Python包、支持相对导入和from package import *、执行包初始化逻辑;Python 3.3+虽引入隐式命名空间包,但无该文件则无法使用相对导入、__all__控制、自动初始化及稳定工具链支持。

Python 3.3+ 的 import 机制变了
根本原因不是“删掉了要求”,而是解释器在 import 时新增了对「隐式命名空间包(implicit namespace package)」的支持。当它找不到带 __init__.py 的目录时,不再直接报错,而是继续检查:该路径下是否纯为子模块集合、且无冲突同名文件(如 mypkg.py)、多个同名目录是否分散在不同 sys.path 位置——满足就组装成一个逻辑包。
不加 __init__.py 的包能干啥?不能干啥?
能:import 成功(只要路径在 sys.path 中),支持跨目录拼接(比如 /a/mypkg/ 和 /b/mypkg/ 同时存在,可合并为一个包);
不能:from mypkg import *(没 __all__ 定义入口)、相对导入(from ..utils import x)、自动执行初始化逻辑、控制子模块暴露范围。
- 空
__init__.py就能启用相对导入和from ... import * - 没有它,
import mypkg.sub可能成功,但from mypkg.sub import func在某些嵌套场景下会失败(尤其涉及测试目录或 IDE 自动补全路径时) - 打包工具如
cx_Freeze、PyInstaller默认不扫描无__init__.py的目录,容易漏模块
为什么很多项目仍坚持加空 __init__.py?
不是为了“兼容老版本”,而是规避现实陷阱:
-
pytest默认只把含__init__.py的目录当包处理,否则test_*.py可能不被发现 - 类型检查器(
mypy、pyright)对 namespace package 支持不稳定,import提示常误报未解析 - 团队协作中,有人用 Python 3.12,有人本地跑 CI 用的是 3.9 镜像——显式加文件比查文档更省心
- 一旦需要加初始化逻辑(比如注册插件、预加载配置),再补
__init__.py往往要改多处导入路径
相对导入失败?先看这两个文件有没有 __init__.py
这是最常被忽略的实操点:只要代码里写了 from ..parent import x 或 from . import sibling,那么当前文件所在目录和目标模块所在目录都必须有 __init__.py(哪怕为空)。缺任意一个,就会报 SystemError: Parent module '' not loaded 或 ImportError: attempted relative import with no known parent package。
立即学习“Python免费学习笔记(深入)”;
比如目录 src/api/__init__.py + src/api/v1/handler.py + src/core/utils.py,若 handler.py 想 from ..core import utils,就必须确保 src/ 和 src/core/ 下都有 __init__.py —— 单靠 src/api/ 里的那个不够。


















