Python 依赖管理工具的研究
太长不读
如果你从事工程项目,poetry 是目前最好的方案,但是如果你不喜欢 Python 的 virtualenv,可以试试 pdm。
混乱的 Python
Python 的依赖管理工具 pip
一直被众多开发者吐槽。从我个人角度,pip
有三点致命缺陷:
- 无法解决 Python 依赖环境的隔离问题
- 依赖管理文件
requirements.txt
无法真正开箱即用 - 打包部署非常麻烦,需要手动配置
环境隔离问题
Python 的依赖库可以安装到系统全局,也可以安装到用户目录(/home/${USER}/.local
)。但如果你同时管理多个 Python 项目,就需要将不同项目的依赖拆分到不同的文件夹分开管理。
传统方式是基于 virtualenv 创建隔离的 Python bin 文件和项目依赖的虚拟环境(所谓虚拟环境并不是虚拟机,只是个绑定 terminal session 的命令环境)。这种方式的缺点是:
- 开发者需要经常关注“我现在处于哪个项目目录?我需要切换到当前虚拟环境里吗?”之类的问题。
- virtualenv 只解决环境隔离,但是无法同步更新依赖文件、打包发布。
依赖安装问题
Python 管理依赖的手段,最早是手动执行pip install xxx
来安装依赖,最后 pip freeze
来导出依赖列表到一个 requirements.txt
文件里。但是这个 txt 文件非常令人困惑。
- 不像 NodeJS 那么方便,想要升、降级某个依赖版本,无法自动同步到 txt 文件里。
- 平铺式地列出了所有一级、二级依赖包(即依赖包的依赖包)。因为 Python 某些依赖又基于系统上安装的 C 库版本,这就导致不同系统环境上执行
pip install -r requirements.txt
得到的效果并不一致,经常报错。
打包部署问题
Python 一般使用 wheel
打包二进制,它只解决打包问题,环境依赖是靠 pip 和 setuptools 完成,所以使用 wheel 你仍然要操心环境隔离和依赖管理问题。
另外基于 Python 各版本之间兼容性问题和底层实现上的不可抗拒力量,wheel 也经常会莫名其妙失败。
现有的解决方案
一直以来,出现过 pipx
,pipenv
, conda
,poetry
以及我最近接触的 pdm
。他们都在某种程度上解决了 Python 的问题,这篇文章:
How to improve Python packaging, or why fourteen tools are at least twelve too many
对比了各种工具的利弊。最后得出结论是 poetry 和 pdm 是目前最合适的工具。而 pdm 是目前唯一支持 PEP 582 的依赖管理工具。
什么是 PEP 582
This PEP proposes to add to Python a mechanism to automatically recognize a
__pypackages__
directory and prefer importing packages installed in this location over user or global site-packages. This will avoid the steps to create, activate or deactivate “virtual environments”. Python will use the__pypackages__
from the base directory of the script when present.
这个 PEP 的目的就是基于一个文件夹 __pypackages__
来管理 Python 的依赖,类似 nodejs 的node_modules
,用户不需要再创建虚拟环境来隔离依赖包。Python 会自动识别和安装依赖。
更新于 2023 年 7 月 2 日:PEP 582 提案已经被拒绝,PDM 暂时仍然支持,但是不建议开发者使用这一特性。
PDM
PDM 实现了 PEP 582!这让我们在解决 Python 依赖问题时不用再考虑虚拟环境。
初始化项目
pdm init
之后 PDM 会问几个问题,记得选择不使用虚拟机环境,这样 PDM 就会默认使用 PEP 582 的解决方案,在项目下生成一个类似 NodeJS 的 __pypackages__
。
剩下的操作就跟 NodeJS 的 npm 非常像了。
添加一个依赖之后,PDM 会自动更新pyproject.toml
文件。
pdm add requests
安装项目依赖
pdm install
启动项目
先在 pyproject.toml
里添加
[tool.pdm.scripts]
start = "flask run -p 54321"
然后执行
pdm run start
打包部署
pdm build
pdm publish
总结
如果你从事科研工作,用 conda
。
如果你从事工程项目,poetry
是目前业内用的最多的方案,大多数情况下它是个不错的依赖管理工具。但是如果你不喜欢 Python 的 virtualenv,pdm
是更好的选择。