uv 完全指南:一个工具干掉 pip + conda + pyenv
uv 是用 Rust 写的 Python 包管理器,比 pip 快 10-100 倍。本文对比 uv、pip、conda、pyenv 的核心差异,附决策流程图和 5 分钟上手命令。
PythonuvPackage Managementpipconda
679  字
2026-04-10

Python 最大的问题不是语法难,是装包难。
如果你写过 Python,一定经历过这些场景:pip install 半天装不上、virtualenv 和 conda 搞混了环境变量、pyenv 编译 Python 等了五分钟结果报错说缺 libffi。这些痛苦不是你的错——是 Python 的包管理生态太碎片化了。pip 管装包、virtualenv 管环境、pyenv 管版本、pip-tools 管锁定……四五个工具各管一摊,还经常互相打架。
2024 年底,一个叫 uv 的工具横空出世,用 Rust 重写了整个 Python 包管理流程。到 2026 年 4 月,它的月下载量已经达到 7500 万次,超过了 Poetry。我的判断是:对于新项目,uv 是 2026 年唯一正确的起点。 这篇文章会告诉你为什么,以及什么时候它不适用。
先搞清楚:这些工具到底各管什么
在对比之前,我们先把这些工具的职责理清楚。很多新手的困惑根源在于:不知道自己需要解决的到底是哪个问题。
Python 开发中有四个核心问题需要解决:
- 装包——把别人写的库下载到本地(pip 的活)
- 环境隔离——项目 A 用 Flask 2.0,项目 B 用 Flask 3.0,互不干扰(virtualenv/venv 的活)
- 版本管理——这台电脑上同时要用 Python 3.9 和 3.12(pyenv 的活)
- 依赖锁定——确保你和同事装的是完全一样的版本(pip-tools/Poetry 的活)
传统方案是每个问题用一个工具解决。问题是:这四个工具的配合从来就不顺畅。pyenv 装的 Python 有时候 pip 找不到,virtualenv 创建的环境有时候 conda 不认,pip freeze 导出的依赖列表里混着直接依赖和间接依赖分不清楚。
uv 的做法是:一个工具全包了。 装包、环境、版本、锁定,全用 uv 一个命令搞定。这不是简单的功能堆砌——它是从底层用 Rust 重写了整个依赖解析和安装流程,所以不仅功能全,而且快得离谱。

真刀真枪:uv vs pip vs conda vs pyenv
光说"好"没用,我们逐项对比。
速度:不是快一点,是快一个数量级

Real Python 的实测数据非常有说服力:安装 JupyterLab,pip 用了 21.4 秒,uv 只要 2.6 秒——8 倍差距。安装一般的 requirements.txt,pip 要 10 秒,uv 只需 2.2 秒。
这个差距来自三个技术决策:并行下载(pip 是串行的)、全局缓存(装过的包不重复下载)、Rust 原生性能(比 Python 实现快几个数量级)。在 CI/CD 流水线里,这个差距会被放大——每次构建都要装依赖,一天跑几十次构建,累计节省的时间非常可观。
conda 的速度介于两者之间。conda 本身不慢,但它要解析的依赖关系更复杂(因为包含非 Python 包),所以体感上比 pip 快不了多少。mamba 是 conda 的加速版,用 C++ 重写了依赖解析,但仍然比 uv 慢。
pyenv 不涉及装包速度,但安装 Python 本身的速度差异巨大:pyenv 从源码编译,一个版本要 3-5 分钟,还经常因为缺少系统库(openssl、libffi、readline)编译失败。uv 直接下载预编译的 Python 二进制文件,实测 2.71 秒装完 PyPy 3.8,跨平台行为一致。
功能覆盖:一个打五个
| 能力 | pip | virtualenv/venv | pyenv | pip-tools | conda | uv |
|---|---|---|---|---|---|---|
| 装包 | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |
| 虚拟环境 | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ |
| Python 版本管理 | ❌ | ❌ | ✅ | ❌ | ✅ | ✅ |
| Lock file | ❌ | ❌ | ❌ | ✅ | ❌ | ✅ |
| 运行脚本/工具 | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ (uvx) |
| 非 Python 依赖 | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
这张表的关键信息是:uv 唯一缺的是非 Python 依赖管理,这恰好是 conda 的核心价值。其他所有能力,uv 一个工具就覆盖了。
依赖管理:pip 的隐藏地雷
这是很多新手没意识到的问题。假设你装了 Flask,pip 会连带装 Werkzeug、Jinja2、MarkupSafe 等间接依赖。现在你卸载 Flask:
pip uninstall flask # 只卸载了 Flask 本身
# Werkzeug、Jinja2、MarkupSafe 全留下了——它们变成了"幽灵依赖"
时间一长,你的环境里堆满了不知道哪来的包,pip freeze 导出的 requirements.txt 里直接依赖和间接依赖混在一起,根本分不清哪些是你真正需要的。这就是为什么"在我机器上能跑"成了 Python 开发者的经典噩梦。
uv 的做法完全不同:
uv add flask # 只记录 Flask 作为直接依赖
uv remove flask # 自动清理所有不再需要的间接依赖
uv sync # 严格按 uv.lock 安装,所有人的环境完全一致
uv.lock 文件精确记录了每个包的版本和哈希值,确保在任何机器上 uv sync 的结果完全相同。这不是什么高级功能,这是 Node.js 的 package-lock.json 十年前就有的东西——Python 生态终于补上了这一课。
决策流程图:你到底该用哪个
别纠结了,跟着这个流程走:
第一步:你是做深度学习/科学计算,需要 CUDA 或非 Python 库吗?
- 是 → 用 conda/mamba 创建基础环境,装好 CUDA 等系统依赖,然后在 conda 环境内用 uv 管理 Python 包。这是 2026 年数据科学的最佳实践。
- 否 → 继续第二步
第二步:你是在维护一个 10 年以上的老项目吗?
- 是 → 先尝试 uv,如果 uv 的严格 resolver 报依赖冲突,再回到 pip。老项目的
pip freeze导出往往有兼容性问题,uv 不会像 pip 那样"宽容"地忽略冲突。 - 否 → 继续第三步
第三步:直接用 uv。 不需要 pyenv,不需要 virtualenv,不需要 pip-tools。一步到位。
用一句话总结我的建议:先试 uv,只有在 uv 解决不了的场景(主要是非 Python 依赖)才引入 conda。 这个策略的风险几乎为零——因为从 uv 迁移回传统工具链非常容易。
5 分钟上手:从安装到跑项目
说了这么多,不如直接上手。以下是从零开始用 uv 的完整流程。
安装 uv
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows PowerShell
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# 如果你已经有 pip(但我不推荐这种方式)
pip install uv
安装完成后,uv 命令就可以用了。不需要重启终端,不需要配置环境变量——这就是 uv 的设计哲学:减少一切不必要的摩擦。
场景一:创建新项目
uv init my-project # 创建项目,自动生成 pyproject.toml
cd my-project
uv add flask requests # 添加依赖,自动创建虚拟环境和 lock file
uv run python app.py # 在虚拟环境中运行
三条命令,项目就跑起来了。对比传统流程:python -m venv .venv && source .venv/bin/activate && pip install flask requests && pip freeze > requirements.txt && python app.py——五条命令,还得手动管理 requirements.txt。
场景二:指定 Python 版本
uv python install 3.12 # 下载 Python 3.12(2-3 秒)
uv init --python 3.12 my-project # 用 3.12 创建项目
对比 pyenv:pyenv install 3.12.0(编译 3-5 分钟,可能因缺库报错),然后 pyenv local 3.12.0(设置目录级版本),然后还得自己创建虚拟环境。
场景三:运行一次性工具
uvx ruff check . # 不用安装,直接跑 ruff 代码检查
uvx black . # 直接跑 black 格式化
uvx jupyter lab # 直接启动 Jupyter Lab
uvx 等同于 pipx run——下载、运行、不污染全局环境。但 uvx 更快,因为有全局缓存。
场景四:从现有 requirements.txt 迁移
uv init my-project
cd my-project
uv add -r requirements.txt # 导入现有依赖
uv sync # 安装并生成 lock file
迁移就是这么简单。原来的 requirements.txt 还在,随时可以回退。
说说 uv 不能做的事
我不喜欢那种只说好话的评测文章。uv 确实优秀,但以下场景你需要知道它的局限:
非 Python 依赖——这是最大的缺口。 如果你的项目需要 CUDA、cuDNN、ffmpeg、或者任何 C/C++ 系统库,uv 帮不了你。conda 的核心价值不是 Python 包管理——是它能把 CUDA 11.8 和 cuDNN 8.9 这种系统级依赖打包成跨平台的 conda 包。这一点 uv 完全无法替代。实操建议:用 conda 只管系统级依赖,Python 包全交给 uv。
企业内网环境需要验证。 如果你在银行、政府等需要过安全审批的环境工作,uv 目前还没有发布 v1.0 正式版(最新是 v0.11.x),某些企业采购流程会卡在版本号上。另外,uv 的离线模式功能还不够完善,在完全断网环境下可能遇到问题。
缓存会占用磁盘空间。 有用户报告使用一年后缓存超过 20GB。虽然 uv cache clean 一条命令就能清理,但在磁盘紧张的 CI 机器上需要注意。
GitHub Dependabot 还不支持 uv.lock。 如果你的安全流程依赖 Dependabot 扫描依赖漏洞,目前 uv 的 lock file 格式还不被支持。这对安全要求高的生产项目是个实际障碍。
VC 支持的公司——这是个争议点。 uv 由 Astral 公司开发,Astral 拿了风投。有人担心将来会不会商业化绑架。我的看法是:uv 是 MIT 协议开源的,即使 Astral 策略变化,社区可以 fork。而且 Astral 同时维护着 Ruff(Python 最快的 linter),他们在开源社区的信誉目前是正面的。这个风险存在,但不应该成为你不用 uv 的理由。
给不同角色的具体建议
Python 新手:直接用 uv,不要碰 pip + virtualenv + pyenv 的组合。你的人生不需要花两小时配环境。uv init → uv add → uv run,三步搞定。
Web 开发者:全面切换 uv。Flask/Django/FastAPI 项目完全在 uv 的能力范围内。uv.lock 会让你的部署环境再也不出"在我机器上能跑"的问题。
数据科学家:conda + uv 混合方案。用 conda 装 Python 和 CUDA 系统依赖,然后 uv pip install 管 Python 包。这比纯 conda 装包快得多。
DevOps/CI 工程师:这是 uv 收益最大的场景。CI 流水线每天跑几十上百次构建,uv 的并行下载和缓存机制能让你的构建时间大幅缩短。在 Dockerfile 里用 uv 替代 pip 是我最推荐的改进之一。
写在最后
Python 包管理的混乱局面持续了十几年。pip、virtualenv、pyenv、pip-tools、Poetry、Pipenv、conda——每个工具解决了一小块问题,但没有一个能让你只学一个工具就搞定所有事情。
uv 是第一个真正做到这件事的工具。它不是又一个"更好的 pip",而是把 Python 包管理该有的所有能力整合到了一个统一的、极其快速的体验里。
我的建议很简单:先试 uv。 如果它解决不了你的问题(极少数情况),再回到你原来用的工具。迁移成本几乎为零,但收益立竿见影。
Related Reading
- Conda Guide: How to Manage Multiple Python Versions and Environments - 如果你需要深入了解 conda 的使用
- uv Official Documentation - uv 的完整官方文档
- A Year of uv: Pros, Cons, and Should You Migrate - 一位开发者使用 uv 一年的深度评测
- uv vs pip - Real Python - Real Python 的详细对比测评
- uv GitHub Repository - uv 的源码和最新动态
Comments
Join the discussion — requires a GitHub account