第1章:requirements.txt — 手动编写与 pip freeze 生成
说实话,我刚入行那会儿,对依赖管理这事完全没当回事。
项目里就一个 requirements.txt,里面躺着几行包名,版本号?不存在的。直到有一次,我在生产环境部署时,发现某个依赖库自动升级了小版本,结果接口行为变了,线上直接报 500。嗯,从那以后,我再也不敢对依赖管理掉以轻心了。
1.1 手动编写 requirements.txt
手动写 requirements.txt,听起来很原始,但有时候反而是最可控的方式。我个人的习惯是:在项目初期,或者依赖数量很少时,直接手写。
格式其实很简单,每行一个包名,可以带版本号:
flask
requests
numpy
但这样写有个问题——你想想看,如果不指定版本,下次别人 pip install -r requirements.txt 时,装到的版本可能跟你本地不一样。这就是我前面说的那个坑的来源。
1.2 pip freeze 生成 — 省心但别无脑用
pip freeze 这个命令,说白了就是把当前环境中所有已安装的包列出来。我经常用它来快速生成依赖清单:
pip freeze > requirements.txt
生成的内容长这样:
click==8.1.3
flask==2.2.2
itsdangerous==2.1.2
jinja2==3.1.2
markupsafe==2.1.1
werkzeug==2.2.2
你看,它把每个包的精确版本都锁死了。这有什么好处?
- 可复现性极强:任何人、任何时间安装,得到的版本完全一致
- 排查问题方便:出 bug 了,我能直接知道当时用的是哪个版本
但这里有个坑——pip freeze 会把所有包都列出来,包括那些你根本没直接引用的依赖。比如你只装了 flask,但它依赖 click、jinja2 等,这些也会被写进去。
pip freeze,最好配合虚拟环境使用。在干净的虚拟环境里只装项目需要的包,再 freeze 出来,这样不会混入无关依赖。
1.3 版本号指定策略
版本号怎么定?这里我总结了三种策略,每种都有它的适用场景。
精确版本 — 用 == 锁定
flask==2.2.2
requests==2.28.1
这是最保守的做法。我在生产环境里几乎都用这种方式。为什么?因为稳定。你想想看,线上系统最怕的就是「昨天还好好的,今天就不行了」。精确锁定版本,能最大程度避免这种意外。
范围版本 — 用 >=、<=、>、<
flask>=2.0.0
requests<3.0.0
numpy>=1.21.0,<1.24.0
这种写法给了依赖一定的「弹性空间」。我一般在开发环境或者库的 setup.py 里用。比如你写了一个开源库,你希望用户能兼容多个版本的依赖,那就用范围指定。
但要注意——范围太宽,可能会踩到版本兼容性的雷。我曾经遇到过 numpy>=1.19 这种写法,结果用户装了 1.24,某些 API 已经废弃了,代码直接报错。
兼容版本 — 用 ~= 和 ==X.*
flask~=2.2.0
requests==2.*
~= 的意思是「兼容版本」。比如 flask~=2.2.0,它会匹配 >=2.2.0, ==2.* 的版本,但不会升级到 2.3.0。说白了,就是只允许补丁版本升级,不允许次版本升级。
==2.* 更宽松一些,只要是 2.x 系列的版本都可以。我个人不太推荐这种,因为 2.0 和 2.9 之间的差异可能已经很大了。
- 生产环境:用
==精确锁定 - 开发环境:用
>=或~=给点弹性 - 开源库:用
>=或~=兼容用户环境
1.4 一张图看懂依赖管理策略
下面这张图,是我自己总结的依赖管理决策流程。每次新项目开始,我都会走一遍这个逻辑:
1.5 实战建议
最后,分享几个我踩过的坑和总结的经验:
- 别混用策略:一个
requirements.txt里,要么全用精确版本,要么全用范围版本。混着写,后期维护起来很头疼。 - 定期更新依赖:我每两个月会跑一次
pip list --outdated,看看哪些包有新版本。但更新前,一定先在测试环境验证。 - 注释很重要:在
requirements.txt里加注释,说明每个包是干什么的。比如:
# Web 框架
flask==2.2.2
# HTTP 请求库
requests==2.28.1
# 数据处理
pandas==1.4.3
requirements.txt 分成两部分——requirements-base.txt(核心依赖)和 requirements-dev.txt(开发工具)。这样部署时只装核心依赖,能减少镜像体积和安装时间。
好了,这一章的内容就到这里。依赖管理看起来是小事,但做好了,能省下大把排查问题的时间。下一章我们会聊聊 Pipfile 和 poetry.lock,看看它们跟 requirements.txt 有什么不同。
可可精品资料库