从 pip 乱装到 uv 统管:一个 Python 开发者的包管理血泪史
我第一次用 Python 的时候,完全不知道什么叫"环境管理"。
pip install numpy,装好了。pip install pandas,装好了。pip install flask,也装好了。感觉一切都很美好,直到某天运行一个旧项目,报错说某个包版本不对,改了版本又把另一个项目搞崩了——两个项目死活不能同时好用。
那时候我就在想:Maven 不是这样的,pnpm 也不是这样的,为什么 Python 这么难用?
◆ ◆ ◆
第一关:全局污染
刚学 Python 的人几乎都会犯同一个错误:直接 pip install,往全局环境装包。
这没什么问题,直到你同时维护多个项目。
项目 A 需要 requests 2.28,项目 B 需要 requests 2.31,全局只能装一个版本,装了新的旧项目报错,装了旧的新项目报错。版本依赖冲突这个坑,几乎每个 Python 新手都会踩。
不只是项目之间,工具之间也会打架。black、ruff、poetry 这些开发工具,底层也依赖各种包,全装在同一个全局环境里,版本一冲突,有时候工具自己就运行不了。
Java 用 Maven,每个项目有自己的 pom.xml,依赖隔离。Node.js 用 npm/pnpm,node_modules 在项目目录里,互不干扰。 为什么 Python 要这么搞?
其实 Python 也有解决方案,只是很多人不知道——那就是 venv。
◆ ◆ ◆
第二关:venv 解决了项目冲突,工具还是一锅粥
python -m venv .venv 一行命令,在项目目录下创建一个独立的 Python 环境。每个项目用自己的 venv,包版本互相隔离,项目之间的冲突问题基本解决了。
但工具类的问题还没完全解决。black、ruff 这些开发工具,你还是得往某个环境里装,装在全局里又回到了冲突的老路,装在每个项目的 venv 里又嫌麻烦——每个项目都要装一遍,而且工具本来是"给人用的",不该绑死在某个项目里。
这时候 pipx 出现了,思路很巧:给每个命令行工具单独创建一个隔离的 venv,工具在自己的小房间里互不打扰,同时把可执行文件注册到系统 PATH,终端里直接调用。
工具之间的包冲突就这样解决了。
直到开始做 AI 开发,新的问题来了。
◆ ◆ ◆
第三关:每个环境都要重复下载 torch,硬盘告急
第一次在项目里装 PyTorch,等了十几分钟,2.几个 GB 下载完,pip install 完成。
第二个 AI 项目,再装 PyTorch,又等了十几分钟。
第三个、第四个……每个 venv 都要单独装一次 PyTorch,每次都是近 3G 的包,每个 venv 占十几个 G,硬盘很快就见底了。
pipx 的隔离 venv 解决了工具冲突,但本质上还是"每个环境各自存一份包"。项目 venv 是这样,pipx 的工具 venv 也是这样,同样的文件在硬盘上存了十几份,没有任何复用。
做 AI 开发的人应该都经历过这种痛苦:光是 torch + torchvision + torchaudio,一套下来就要 35G,10 个项目就是 3050G 白白浪费在重复的文件上。
◆ ◆ ◆
终局:uv 才是真正的答案
后来接触到 uv,用了之后就再也回不去了。
uv 是用 Rust 写的 Python 包管理工具,速度极快(比 pip 快 10~100 倍),但速度还不是它最让我惊喜的地方。
真正让我眼前一亮的是它的全局缓存 + 硬链接机制。
装过一次的包,下次再装直接从缓存里读,不下载、不复制,而是用硬链接。硬链接意味着同一份文件在文件系统里被多个位置"共享引用",不占额外空间。
十个项目都用 torch?全局缓存里只有一份 torch,10 个项目的 venv 里都通过硬链接指向同一份文件,磁盘占用从 30G 变成 3G。
这才是我一直想要的,和 pnpm 的 store 机制一模一样的思路。而且 uv 把 venv、工具管理、Python 版本管理全部统一进来了,不再需要 venv + pipx 两套工具拼凑。
◆ ◆ ◆
uv 的使用方式
第一步:安装 uv
uv 本身是独立的 Rust 二进制,不依赖系统已有的 Python 或 pip,直接一行安装:
# Windows PowerShellirm https://astral.sh/uv/install.ps1 | iex# macOS / Linuxcurl -LsSf https://astral.sh/uv/install.sh | sh
装完验证一下:uv --version,出现版本号就好了。
第二步:用 uv 管理 Python 版本
以前装多个 Python 版本,要么去官网手动下载,要么用 pyenv(Windows 上还不太好用)。uv 直接内置了 Python 版本管理:
# 安装指定版本uv python install 3.11uv python install 3.12# 查看所有已安装版本uv python list
系统里不需要提前装任何 Python,uv 自己全管了。
第三步:创建项目环境
# 创建虚拟环境(默认用已有 Python,没有会自动下载)uv venv# 指定版本uv venv --python 3.11# 安装依赖uv add torch numpy pandas# 从 requirements.txt 安装uv pip install -r requirements.txt
‣ 不需要手动激活 venv
原生 venv 最繁琐的一步就是每次都要 source .venv/bin/activate 或者 Windows 下执行激活脚本,忘了就报"找不到包"。
uv 的所有命令会自动检测当前目录下的 .venv,不需要手动激活:
# 直接运行,uv 自动找到并使用 .venvuv run python main.pyuv run pytestuv run jupyter notebook
当然你也可以手动激活,进入激活状态后 python、pip 等命令也照常工作,和原生 venv 完全兼容。
uv tool:统一管理全局工具
uv tool 是内置的工具管理功能,完全替代 pipx,同样是隔离 venv 安装,同样全局可调用,但共享 uv 的全局缓存:
# 安装工具(最新版)uv tool install blackuv tool install ruff# 安装指定版本uv tool install "ruff>=0.3,<0.4"# 查看已安装的工具uv tool list# 升级uv tool upgrade ruffuv tool upgrade --all
安装了某个工具之后,如果某次需要临时用一个不同版本,可以用 @ 语法指定,不会影响已安装的版本:
# 用已安装的版本ruff check .# 临时用特定版本运行(不影响已安装版本)uvx ruff@0.3.0 check .uvx ruff@latest check .
uvx:临时运行,用完即走
uvx 是 uv tool run 的简写,不需要提前安装工具,直接运行,非常适合偶尔用一次的场景:
uvx black . # 临时跑一次 blackuvx ruff check . # 临时跑一次 ruffuvx pytest # 临时跑测试
如果包名和命令名不一样,用 --from 指定:
uvx --from httpie http GET https://example.com
◆ ◆ ◆
一点感慨
用 Python 这几年,包管理的演进路径大概是这样的:
pip 全局安装 → 版本冲突 → 发现 venv,项目隔离了 → 工具还是互相污染 → 发现 pipx,工具也隔离了 → 开始 AI 开发,每个 venv 重复存 torch,硬盘告急 → 发现 uv,全局缓存硬链接,终于和 maven/pnpm 一样舒服了
中间走了很多弯路。其实如果一开始就用 uv,很多坑根本不用踩——从一开始就安装 uv,让 uv 来管 Python 版本,创建项目 venv,安装管理工具,全部由一个工具统管,干净利落。
如果你还在用原生 pip,或者正在为 torch 重复下载烦恼,建议现在就去试试 uv。
◆ ◆ ◆
uv 官方文档:https://docs.astral.sh/uv
次条附 uv 速查表,收藏备用。