当一段代码开始在不同项目里重复出现时,把它做成一个真正可安装、可复用的 Python 包,往往比复制粘贴更值得。包化不仅是复用方式的升级,也是工程边界更清晰的一种表现。
这一节我们会从构建产物、元信息、版本号、入口命令到发布流程,完整梳理一个 Python 包是如何从本地代码变成团队或社区可以消费的工具的。
为什么要把代码做成包?
复制粘贴当然很快,但它会把问题越积越多:
- 修一个 bug 要改多个项目;
- 版本不一致;
- 没人知道哪份才是权威实现;
- 复用关系全靠记忆。
而包化意味着你开始明确这段代码的边界:
- 它对外暴露什么;
- 它依赖什么;
- 它如何被安装和升级;
- 它的版本如何演进。
这比“代码复用”更进一步,因为它是在做真正的交付单元设计。
pyproject.toml 中的关键信息
现代 Python 包的元信息通常集中在 pyproject.toml 中。
这里面最关键的通常包括:
- 包名;
- 版本;
- 描述信息;
- Python 版本要求;
- 运行依赖;
- 可选开发依赖;
- 构建后端。
也就是说,pyproject.toml 不只是一个配置文件,它几乎就是这个包的“身份证”。
别人要理解你的包是什么、怎么安装、依赖什么,很多时候第一眼看的就是这里。
构建产物:sdist 与 wheel
Python 包构建后,常见会生成两类产物:
sdist:源码分发包;wheel:构建好的二进制分发格式。
你可以先把它们理解成:
sdist更接近“原材料”;wheel更接近“可直接安装的成品”。
在大多数现代发布流程里,wheel 通常是更常被优先消费的形式,因为安装更快、更稳定。
理解这一层的意义,不是要求你自己手写所有构建细节,而是知道包发布并不是“把源码传上去”这么简单,它背后有标准化产物和分发流程。
版本号、入口命令与依赖声明
一个可复用包真正能被别人顺畅消费,至少要把三件事说清楚。
第一是版本号。版本号不是装饰,而是兼容性承诺的一部分。使用者会通过它判断能不能升级、升级后风险大不大。
第二是入口命令。如果你的包是 CLI 工具,那就需要明确安装后用户如何直接执行命令,而不是还要自己找模块路径。
第三是依赖声明。包依赖哪些第三方库,哪些是运行时必需,哪些是开发时才需要,都应该清楚表达。
换句话说,包发布不是“让代码能装”,而是“让代码被别人合理理解和使用”。
发布到私有源或 PyPI 的基本流程
从流程上看,包发布通常包括:
- 确认元信息和版本;
- 构建产物;
- 本地安装验证;
- 上传到目标源;
- 在真实环境里按发布方式重新安装验证。
至于目标源是私有仓库还是公开 PyPI,取决于你的复用范围和分发策略。但不管发到哪里,关键都不是“传上去”,而是发布前后是否可验证、可回滚、可追踪。
包发布前的常见检查项
包发布最怕的不是“功能没写完”,而是“本地能用,发出去就坏”。
所以发布前至少应该检查:
- 版本是否正确递增;
- 依赖是否声明完整;
- 入口命令是否正常;
- 关键 API 是否稳定;
- README 或使用说明是否跟当前版本一致。
这些检查的意义在于:包一旦发布,你就不只是对自己负责,而是在对外提供一个承诺。
总结与预告
这一节我们把“代码复用”从复制粘贴升级成了真正的包发布流程,理解了构建产物、版本号、依赖声明和发布渠道之间的关系。做成包之后,代码的边界和责任也会变得更加明确。
接下来我们会短暂停下来,集中处理一批 Python 开发里最容易踩到、也最值得提前理解的性能与行为陷阱。