在这里插入图片描述

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

在阅读 Python 项目代码时,你一定见过很多这样的文件:

__init__.py

很多人刚接触 Python 时都会有几个疑问:

  • 这个文件为什么叫 __init__
  • 为什么有的项目里有,有的项目里没有?
  • 里面到底应该写什么?
  • 不写会怎么样?

其实,__init__.pyPython 包(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

这里:

  • utilspackage
  • file.py / math.pymodule

有了 __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_file
  • add

而不会导入其他内部函数。

📌 这是 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 的模块系统有更深入的理解。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐