Python 中的 `__init__.py` 到底是干什么的?从入门到工程实践

Python 中的 __init__.py 到底是干什么的?从入门到工程实践
在阅读 Python 项目代码时,你一定见过很多这样的文件:
__init__.py
很多人刚接触 Python 时都会有几个疑问:
- 这个文件为什么叫
__init__? - 为什么有的项目里有,有的项目里没有?
- 里面到底应该写什么?
- 不写会怎么样?
其实,__init__.py 是 Python 包(package)机制中非常重要的一部分。理解它,对阅读大型项目(例如 FastAPI、Django、PyTorch 等)非常有帮助。
本文我们从 基础原理 → 实际用途 → 工程实践 一步一步讲清楚。
一、先看一个最简单的例子
假设有这样一个目录结构:
project
├── main.py
└── utils
└── tool.py
tool.py
def hello():
print("hello")
如果 utils 目录 没有 __init__.py,在早期 Python 版本(❤️.3)中,你会遇到:
import utils.tool
可能直接报错。
因为:
Python 需要通过
__init__.py判断一个目录是不是“包”。
二、什么是 Python 包(Package)
在 Python 中:
| 类型 | 含义 |
|---|---|
| module | 一个 .py 文件 |
| package | 一个包含多个模块的目录 |
例如:
project
├── main.py
└── utils
├── __init__.py
├── file.py
└── math.py
这里:
utils是 packagefile.py/math.py是 module
有了 __init__.py,Python 才会把这个目录当作 可导入的包。
三、__init__.py 最简单的作用
很多项目里的 __init__.py 是 空文件:
# __init__.py
即使是空的,也有意义。
📌 作用:
告诉 Python:这个目录是一个 package。
四、导入时 __init__.py 会自动执行
很多人不知道的一点是:
当 package 被 import 时,
__init__.py会自动执行。
例如:
project
└── utils
├── __init__.py
└── tool.py
__init__.py
print("utils package loaded")
当执行:
import utils
输出:
utils package loaded
所以:
__init__.py 本质上就是包的初始化脚本。
这也是为什么它叫:
__init__
和类的 __init__ 概念类似。
五、统一包的对外接口(非常常见)
这是 __init__.py 最重要的工程用途之一。
例如:
project
└── utils
├── __init__.py
├── file.py
└── math.py
file.py
def read_file():
pass
math.py
def add(a, b):
return a + b
如果没有 __init__.py:
from utils.file import read_file
from utils.math import add
如果在 __init__.py 中写:
from .file import read_file
from .math import add
那么就可以直接:
from utils import read_file, add
代码会更简洁。
很多知名库都是这么做的 👍
六、控制 import * 导出内容
__init__.py 还可以控制:
from package import *
导入哪些内容。
通过:
__all__
示例:
# __init__.py
from .file import read_file
from .math import add
__all__ = ["read_file", "add"]
这样:
from utils import *
只会导入:
read_fileadd
而不会导入其他内部函数。
📌 这是 Python 库设计中非常常见的做法。
七、在 __init__.py 中做初始化工作
有些项目会在这里做一些初始化,例如:
- 日志配置
- 注册插件
- 初始化变量
- 版本信息
例如:
# __init__.py
import logging
logging.basicConfig(level=logging.INFO)
VERSION = "1.0.0"
然后可以这样使用:
import utils
print(utils.VERSION)
八、Python 3.3 之后的新变化
从 Python 3.3 开始,引入了一个新概念:
Namespace Package
这意味着:
没有
__init__.py的目录也可以成为 package。
例如:
utils/
tool.py
依然可以:
import utils.tool
但是在实际工程中:
⚠️ 仍然建议保留 __init__.py
原因:
- 兼容旧 Python
- 方便统一接口
- 可以写初始化逻辑
- 工程结构更清晰
九、真实项目中的典型结构
例如一个 Web 服务:
project
├── main.py
└── app
├── __init__.py
├── api
│ ├── __init__.py
│ └── user.py
└── service
├── __init__.py
└── auth.py
app/__init__.py
from .service.auth import login
这样在 main.py 中:
from app import login
而不用写:
from app.service.auth import login
是不是清爽很多? 😄
十、一个常见的最佳实践
很多成熟项目会这样写 __init__.py:
"""
Utilities package
"""
from .file import read_file
from .math import add
__all__ = ["read_file", "add"]
优点:
✅ 控制导出接口
✅ 简化 import
✅ 隐藏内部实现
十一、什么时候需要写 __init__.py?
一般来说有三种情况:
1️⃣ 标记 package
最基础用途。
folder/
__init__.py
2️⃣ 统一模块接口
package/
__init__.py
module1.py
module2.py
3️⃣ 包初始化
例如:
- 注册组件
- 初始化配置
- 加载插件
十二、总结
__init__.py 是 Python 包系统中的一个核心文件。
它主要有四个作用:
| 作用 | 说明 |
|---|---|
| 标记 package | 让 Python 识别目录为包 |
| 包初始化 | import 时执行 |
| 统一接口 | 简化 import |
| 控制导出 | 使用 __all__ |
一个简单但推荐的写法:
from .module import func
__all__ = ["func"]
虽然在 Python 3.3+ 中它不再是 必须的,但在真实工程项目中:
💡 绝大多数项目仍然会保留 __init__.py。
因为它不仅是一个标记文件,更是 Python 包设计的重要入口。
如果你经常阅读开源项目(比如 FastAPI、Flask、Django、Whisper 等),你会发现:
优秀的 Python 项目,几乎都会认真设计
__init__.py。
理解它,会让你对 Python 的模块系统有更深入的理解。
更多推荐



所有评论(0)