3. 依赖管理:从混乱到有序
依赖管理这事儿,说白了就是管好你项目里的「外来户」。每个 Python 项目都会引入第三方库,这些库之间还有自己的依赖关系。我见过太多项目因为依赖没管好,部署时直接崩掉。嗯,今天我们就来彻底搞定它。
3.1 requirements.txt:项目的「购物清单」
我个人习惯,每个项目根目录下必须有一个 requirements.txt。它就像一张购物清单,记录了你项目需要哪些包、什么版本。
最简单的生成方式:
pip freeze > requirements.txt
这命令会把当前环境里所有已安装的包都列出来。但要注意——它会把你无意中装过的包也列进去。我在项目中遇到过这种情况:明明只用了 Flask,结果 requirements.txt 里多出几十个无关包。为什么?因为 pip 会把所有依赖的依赖也列出来。
更推荐的做法是手动维护:
# requirements.txt
flask==2.3.0
requests==2.31.0
numpy>=1.24.0
安装依赖时,一行命令搞定:
pip install -r requirements.txt
== 锁定精确版本,用 >= 指定最低版本。别用 *,那等于没写。
3.2 pip freeze 的正确打开方式
pip freeze 是个好工具,但用不好会坑人。它输出的是当前环境的「快照」。你想想看,如果你在全局环境里跑这个命令,那列出来的包可能跟你的项目半毛钱关系都没有。
正确的做法:
- 先创建虚拟环境(比如 venv 或 conda)
- 在虚拟环境里安装项目需要的包
- 再执行
pip freeze > requirements.txt
我曾经犯过一个错:在全局环境里 freeze 后,把文件发给同事。结果同事一安装,版本冲突炸了。从那以后,我每次都会先确认自己在虚拟环境里。
--platform 参数指定平台。
3.3 依赖冲突:排查与解决
依赖冲突,说白了就是「包 A 要 Flask 2.0,包 B 要 Flask 1.0」。两个包都想要,但 Flask 只能装一个版本。这时候 pip 会报错,告诉你「无法满足依赖关系」。
排查步骤:
- 看错误信息——pip 会告诉你哪个包冲突了
- 用
pip check检查当前环境的依赖是否完整 - 用
pipdeptree查看依赖树
安装 pipdeptree:
pip install pipdeptree
pipdeptree
输出示例:
flask==2.3.0
- click [required: >=8.0, installed: 8.1.3]
- itsdangerous [required: >=2.0, installed: 2.1.2]
requests==2.31.0
- urllib3 [required: >=1.21.1,<3, installed: 2.0.0]
看到没?依赖关系一目了然。哪个包依赖了哪个版本,清清楚楚。
解决冲突的常见方法:
| 方法 | 适用场景 | 操作 |
|---|---|---|
| 升级/降级 | 某个包版本过旧或过新 | pip install package==指定版本 |
| 替换包 | 两个包功能重叠 | 换一个功能类似的包 |
| 使用约束文件 | 需要全局控制版本 | 创建 constraints.txt |
3.4 pip-tools:让依赖管理更优雅
手动维护 requirements.txt 很累,pip freeze 又不够精确。这时候,pip-tools 就派上用场了。
安装:
pip install pip-tools
它的工作流程是这样的:
- 你写一个
requirements.in文件,只列出顶层依赖 - 运行
pip-compile,自动生成完整的requirements.txt - 运行
pip-sync,让环境与 requirements.txt 完全一致
举个例子,requirements.in 内容:
flask
requests
然后执行:
pip-compile requirements.in
它会自动生成 requirements.txt,里面包含了所有依赖的依赖,并且版本都锁定了:
# This file is autogenerated by pip-compile
click==8.1.3
# via flask
flask==2.3.0
# via -r requirements.in
itsdangerous==2.1.2
# via flask
requests==2.31.0
# via -r requirements.in
urllib3==2.0.0
# via requests
看到没?它连「谁依赖了谁」都给你标注出来了。我个人非常喜欢这个功能,排查依赖关系时特别方便。
更新依赖也很简单:
pip-compile --upgrade-package flask # 只升级 flask
pip-compile --upgrade # 升级所有包
requirements.in 提交到 Git,但 requirements.txt 也提交。这样别人 clone 项目后,直接 pip install -r requirements.txt 就能复现环境。
3.5 依赖管理的完整流程
最后,我总结一下一个靠谱的依赖管理流程:
- 创建虚拟环境(venv 或 conda)
- 在
requirements.in里写顶层依赖 - 运行
pip-compile生成requirements.txt - 运行
pip-sync同步环境 - 把两个文件都提交到版本控制
- 每次新增依赖,重复步骤 2-4
这样做的好处是:你永远知道项目依赖了什么,版本不会乱,同事也不会因为环境不一致而抓狂。
pip freeze 的输出直接当 requirements.txt 用。我见过有人这么干,结果部署时发现少了一个包——因为那个包在开发环境里是全局安装的,根本没写在 requirements 里。
依赖管理看似小事,但做不好会浪费大量时间。嗯,希望今天的内容能帮你少踩几个坑。