Python 包结构基础:init.py 作用

文章目录

    • 前言
    • [一、init.py 到底是什么?](#一、init.py 到底是什么?)
    • [二、init.py 的五大核心作用(2026最新版)](#二、init.py 的五大核心作用(2026最新版))
      • [2.1 作用一:声明文件夹为Python包(基础)](#2.1 作用一:声明文件夹为Python包(基础))
      • [2.2 作用二:控制包的导入暴露(all 变量)](#2.2 作用二:控制包的导入暴露(all 变量))
      • [2.3 作用三:简化导入路径(最实用的工程技巧)](#2.3 作用三:简化导入路径(最实用的工程技巧))
      • [2.4 作用四:包初始化逻辑(启动时执行)](#2.4 作用四:包初始化逻辑(启动时执行))
      • [2.5 作用五:隐藏内部实现,对外提供稳定API](#2.5 作用五:隐藏内部实现,对外提供稳定API)
    • [三、Python 3.10+ 下 init.py 的新变化(2026重点)](#三、Python 3.10+ 下 init.py 的新变化(2026重点))
      • [3.1 空 init.py 完全合法](#3.1 空 init.py 完全合法)
      • [3.2 命名空间包不需要 init.py,但不推荐业务使用](#3.2 命名空间包不需要 init.py,但不推荐业务使用)
      • [3.3 init.py 中禁止写复杂业务逻辑](#3.3 init.py 中禁止写复杂业务逻辑)
      • [3.4 推荐搭配 pyproject.toml 使用](#3.4 推荐搭配 pyproject.toml 使用)
    • [四、init.py 最佳实践(直接照抄用)](#四、init.py 最佳实践(直接照抄用))
      • [4.1 最简空包(推荐)](#4.1 最简空包(推荐))
      • [4.2 带 all 控制导入](#4.2 带 all 控制导入)
      • [4.3 简化导入(最常用)](#4.3 简化导入(最常用))
      • [4.4 带版本信息](#4.4 带版本信息)
      • [4.5 懒加载高级写法(2026流行)](#4.5 懒加载高级写法(2026流行))
    • [五、新手最容易踩的 init.py 坑](#五、新手最容易踩的 init.py 坑)
      • [5.1 坑1:忘记写 init.py,导入失败](#5.1 坑1:忘记写 init.py,导入失败)
      • [5.2 坑2:循环导入](#5.2 坑2:循环导入)
      • [5.3 坑3:all 写错,导致 import * 失效](#5.3 坑3:all 写错,导致 import * 失效)
      • [5.4 坑4:在 init.py 写大量代码,导致导入极慢](#5.4 坑4:在 init.py 写大量代码,导致导入极慢)
      • [5.5 坑5:把 init.py 当成普通业务文件用](#5.5 坑5:把 init.py 当成普通业务文件用)
    • 六、真实项目结构示例(2026标准)
    • [七、总结:一句话记住 init.py](#七、总结:一句话记住 init.py)

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,[传送门https://blog.csdn.net/HHX_01\],(https://blog.csdn.net/HHX_01/article/details/159613021)

前言

很多刚学Python的小伙伴都会遇到一个灵魂拷问:为什么我写的模块别人能导入,我自己写的包就死活导入失败? 排查半天,最后发现只是少了一个 __init__.py 文件。

在Python开发中,__init__.py 可以说是最常见又最容易被忽略的文件。尤其是2026年现在,Python 3.10+已经全面普及,命名空间包、pyproject.tomlimportlib 等新特性层出不穷,很多人还在用十年前的旧写法,不仅代码臃肿,还容易踩坑。

这篇文章我就用最通俗、最接地气的方式,把 __init__.py作用、用法、新版变化、最佳实践、避坑指南一次性讲透。不管你是刚入门的小白,还是工作多年的老开发,都能从中找到能直接用在项目里的干货。

一、init.py 到底是什么?

简单一句话:
__init__.py 是Python用来标识一个文件夹为「标准包(Package)」的标记文件。

在没有 __init__.py 之前,一个文件夹只是普通文件夹,Python 不会把它当成包来识别,你也无法正常 import 里面的模块。

举个最直观的例子:

复制代码
my_project/
├── utils/
│   ├── math.py
│   └── string.py
└── main.py

如果你在 main.py 里写:

python 复制代码
import utils.math

Python 会直接报错:ModuleNotFoundError

但只要在 utils 文件夹里加一个空的 __init__.py

复制代码
my_project/
├── utils/
│   ├── __init__.py
│   ├── math.py
│   └── string.py
└── main.py

再导入就完全正常了。

这就是 __init__.py 最基础、最核心的作用:声明这是一个Python包

二、init.py 的五大核心作用(2026最新版)

很多老教程只讲"标记包",但在现代Python开发中,__init__.py 的作用远不止于此。下面我按实际开发频率从高到低,把五大核心作用讲清楚。

2.1 作用一:声明文件夹为Python包(基础)

这是最原始、最必须的作用。只要你想让一个文件夹变成可导入的包,就必须有 __init__.py

注意:

从 Python 3.3+ 开始,引入了命名空间包(Namespace Package) ,可以没有 __init__.py 也能导入。但在实际工程、发布包、公司项目 中,99% 仍然推荐使用 __init__.py,因为命名空间包有很多隐式坑,不适合小白和标准工程。

2026年的主流规范依然是:
业务项目必须写 __init__.py,库开发建议保留。

2.2 作用二:控制包的导入暴露(all 变量)

这是 __init__.py 最常用、最重要的功能,没有之一。

你一定见过这种写法:

python 复制代码
# utils/__init__.py
__all__ = ["math", "string"]

它的作用是:
当别人使用 from utils import * 时,只导入 __all__ 列表里的模块。

没有 __all__* 导入行为是混乱且不可控的。

真实开发场景示例:

python 复制代码
# utils/math.py
def add(a, b):
    return a + b

def minus(a, b):
    return a - b

# utils/string.py
def upper(s):
    return s.upper()

# utils/__init__.py
__all__ = ["math", "string"]

在外部使用:

python 复制代码
from utils import *

print(math.add(1, 2))
print(string.upper("hello"))

非常干净、规范。

如果没有 __all__import * 可能会导入内部变量、测试函数、私有模块,导致命名冲突。

2.3 作用三:简化导入路径(最实用的工程技巧)

这是中高级开发者必用的技巧,可以让用户不用写冗长的层级导入

比如原本结构:

复制代码
my_lib/
├── __init__.py
├── core/
│   ├── __init__.py
│   ├── calculator.py

calculator.py 里有一个 Calculator 类。

正常导入要写:

python 复制代码
from my_lib.core.calculator import Calculator

又臭又长。

我们可以在 my_lib/core/__init__.py 里写:

python 复制代码
from .calculator import Calculator

再在 my_lib/__init__.py 写:

python 复制代码
from .core import Calculator

外部用户只需要:

python 复制代码
from my_lib import Calculator

层级被彻底抹平,使用体验大幅提升。

这也是2026年主流开源库(如FastAPI、Pandas、Polars)的标准做法

2.4 作用四:包初始化逻辑(启动时执行)

__init__.py包第一次被导入时会自动执行,所以可以用来做初始化操作。

例如:

  • 加载配置
  • 初始化日志
  • 检查环境
  • 注册插件
  • 预加载模型

示例:

python 复制代码
# my_lib/__init__.py
import logging
import os

# 包初始化时执行
print("my_lib 正在初始化...")

# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("my_lib")

# 读取环境配置
VERSION = "1.0.0"
DEBUG = os.getenv("MY_LIB_DEBUG", "0") == "1"

外部导入时:

python 复制代码
import my_lib
# 自动输出:my_lib 正在初始化...

注意:
初始化逻辑不要太重,2026年的最佳实践是尽量懒加载,避免拖慢导入速度。

2.5 作用五:隐藏内部实现,对外提供稳定API

大型项目一定会区分:

  • 公开接口(public):给用户用
  • 内部实现(private):自己用,不对外暴露

__init__.py 就是最好的隔离层

示例结构:

复制代码
ai_toolkit/
├── __init__.py
├── _internals/
│   ├── __init__.py
│   ├── engine.py
│   └── utils.py
└── api.py

_internals 是内部实现,不希望用户直接导入。

我们在 ai_toolkit/__init__.py 只暴露公开API:

python 复制代码
from .api import ModelInfer, Tokenizer

用户只能这样用:

python 复制代码
from ai_toolkit import ModelInfer

无法直接导入 _internals,保证了代码安全与后续重构自由。

三、Python 3.10+ 下 init.py 的新变化(2026重点)

到了2026年,Python 3.10及以上版本成为绝对主流,__init__.py 也有了很多现代化变化。

3.1 空 init.py 完全合法

很多人强迫症喜欢删空文件,但保留空 __init__.py 是现代Python标准规范,不影响性能,也不冗余。

3.2 命名空间包不需要 init.py,但不推荐业务使用

命名空间包适合分发包、多模块联合包,但业务系统用起来容易出现:

  • 导入路径混乱
  • 无法控制 __all__
  • 无法做初始化
  • IDE识别错乱

所以公司项目一律用传统带 init.py 的包

3.3 init.py 中禁止写复杂业务逻辑

现代Python强调懒加载__init__.py 只做三件事:

  1. 导出公开API
  2. 定义元信息(versionauthor
  3. 极简初始化

不要再写循环、IO、网络请求、 heavy计算在 __init__.py 里。

3.4 推荐搭配 pyproject.toml 使用

2026年打包标准是 pyproject.toml__init__.py 负责运行时导出,pyproject.toml 负责构建时配置。

示例:

toml 复制代码
[project]
name = "my_utils"
version = "0.1.0"

__init__.py 中:

python 复制代码
__version__ = "0.1.0"

保持一致即可。

四、init.py 最佳实践(直接照抄用)

我把2026年工业界最标准的写法整理成模板,你可以直接复制到项目中。

4.1 最简空包(推荐)

python 复制代码
# __init__.py
# 空文件即可

4.2 带 all 控制导入

python 复制代码
__all__ = [
    "math",
    "string",
    "file"
]

4.3 简化导入(最常用)

python 复制代码
from .core import Engine
from .api import predict
from .utils import Config

__all__ = ["Engine", "predict", "Config"]

4.4 带版本信息

python 复制代码
__version__ = "1.0.0"
__author__ = "AI开发者"

from .model import MyModel
__all__ = ["MyModel"]

4.5 懒加载高级写法(2026流行)

避免启动慢:

python 复制代码
from importlib import lazy_import

__all__ = ["Model"]

Model = lazy_import(".model").Model

导入时不加载,第一次使用才加载。

五、新手最容易踩的 init.py 坑

5.1 坑1:忘记写 init.py,导入失败

这是小白第一大坑。只要是包,必须加 __init__.py

5.2 坑2:循环导入

__init__.py 导入子模块,子模块又导入包,导致死循环。

解决方案:

  • 简化 __init__.py
  • 使用懒加载
  • 调整依赖关系

5.3 坑3:all 写错,导致 import * 失效

__all__ 是字符串列表,写错名字就会找不到模块。

5.4 坑4:在 init.py 写大量代码,导致导入极慢

现代Python追求极速导入,初始化逻辑尽量丢到内部模块。

5.5 坑5:把 init.py 当成普通业务文件用

它是包声明文件,不是业务逻辑文件,不要写函数实现。

六、真实项目结构示例(2026标准)

给你一个可直接用于生产的完整结构:

复制代码
my_ai_project/
├── my_ai/
│   ├── __init__.py       # 导出API
│   ├── core/
│   │   ├── __init__.py
│   │   └── engine.py
│   ├── utils/
│   │   ├── __init__.py
│   │   ├── log.py
│   │   └── config.py
│   └── api.py
├── pyproject.toml
└── main.py

my_ai/__init__.py:

python 复制代码
__version__ = "1.0.0"

from .core.engine import AIEngine
from .api import inference
from .utils.config import Settings

__all__ = ["AIEngine", "inference", "Settings"]

外部使用:

python 复制代码
from my_ai import AIEngine, inference, Settings

干净、优雅、专业。

七、总结:一句话记住 init.py

  • 标记包:告诉Python这是一个包
  • 控制暴露 :用 __all__ 管理导入
  • 简化路径:让用户少写层级
  • 初始化:包启动时执行一次
  • 隔离实现:保护内部代码

2026年的Python开发,__init__.py 不是过时产物,而是包结构设计的核心枢纽。写好它,你的项目结构会清晰十倍,别人用你的包也会爽十倍。

只要按照本文的规范去写,你再也不会遇到导入失败、结构混乱、规范不统一的问题。

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,[传送门https://blog.csdn.net/HHX_01\],(https://blog.csdn.net/HHX_01/article/details/159613021)

相关推荐
寂寞旅行2 小时前
模型蒸馏: 小模型也有“大用“
人工智能·embedding
财迅通Ai10 小时前
商业航天概念领涨A股,航天ETF华安(159267.SZ)收盘上涨1.2%
大数据·人工智能·区块链·中国卫星·航天电子
齐齐大魔王10 小时前
智能语音技术(八)
人工智能·语音识别
许彰午10 小时前
零成本搭建RAG智能客服:Ollama + Milvus + DeepSeek全程实战
人工智能·语音识别·llama·milvus
ZPC821010 小时前
自定义action server 接收arm_controller 指令
人工智能·机器人
迷茫的启明星11 小时前
各职业在当前发展阶段,使用AI的舒适区与盲区
大数据·人工智能·职场和发展
Liqiuyue12 小时前
Transformer:现代AI革命背后的核心模型
人工智能·算法·机器学习
桂花饼12 小时前
AI 视频生成:sora-2 模型快速对接指南
人工智能·音视频·sora2·nano banana 2·claude-opus-4-6·gemini 3.1