uv:新一代 Python 包管理器,快到离谱
「Python 包管理全攻略」系列第五篇。今天聊一个让整个 Python 社区都兴奋的工具------uv。
uv 是什么来头?
uv 是 Astral 公司用 Rust 写的 Python 包管理器和项目管理工具。Astral 就是做 Ruff(超快的 Python linter)的那个团队。
一句话概括 uv:它是一个更快的 pip + venv + pyenv + pip-tools + poetry 的集合体。
不是夸张,uv 真的想把这些工具全部替代。
到底有多快?
不废话,上对比:
bash
# 用 pip 安装 50 个包
time pip install -r requirements.txt
# 约 15-30 秒
# 用 uv 安装同样的 50 个包
time uv pip install -r requirements.txt
# 约 0.5-2 秒
10-100 倍的速度差距,不是基准测试里的数字,是你日常使用中的实际体验。
为什么这么快?
- Rust 写的,没有 Python 的解释器开销
- 全局缓存,同样的包不用重复下载和解压
- 并行下载和安装
- 高效的依赖解析算法
安装 uv
bash
# 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 安装(但不推荐,因为 uv 就是替代 pip 的,有点套娃)
pip install uv
装完验证:
bash
uv --version
uv 的第一种用法:替代 pip
这是最简单的上手方式,你不用改变任何工作习惯,只是把 pip 换成 uv pip:
bash
# 创建虚拟环境(替代 python -m venv)
uv venv
# 激活虚拟环境(和之前一样)
source .venv/bin/activate
# 装包(替代 pip install)
uv pip install flask requests
# 指定版本
uv pip install "flask>=3.0.0"
# 从 requirements.txt 安装
uv pip install -r requirements.txt
# 导出
uv pip freeze > requirements.txt
# 卸载
uv pip uninstall flask
# 查看已装的包
uv pip list
命令几乎一模一样,只是前面多了个 uv,速度快了几十倍。就这一步,就能让你日常开发效率提升不少。
uv 的第二种用法:项目管理
uv 不只是 pip 的替代品,它还是一个完整的项目管理工具,类似 Poetry 或 PDM。
初始化项目
bash
mkdir my-project && cd my-project
uv init
这会生成以下结构:
perl
my-project/
├── pyproject.toml # 项目配置和依赖声明
├── README.md
├── hello.py
└── .python-version # Python 版本锁定
管理依赖
bash
# 添加依赖
uv add flask
uv add "requests>=2.31.0"
uv add pytest --dev # 开发依赖
# 移除依赖
uv remove flask
# 同步环境(安装所有声明的依赖)
uv sync
每次 uv add 或 uv remove 都会自动更新 pyproject.toml 和 uv.lock,不需要手动管理 requirements.txt 了。
运行命令
bash
# 在虚拟环境中运行脚本
uv run python app.py
# 运行项目中的模块
uv run python -m my_project
# 直接运行(uv 自动确保环境就绪)
uv run flask run
uv run 是个很聪明的命令------它会自动检查环境,如果依赖没装或者 lock 文件有变化,会先同步环境再执行。你再也不用担心"哦我忘了 pip install 了"这个问题。
锁定依赖
bash
# 生成/更新 lock 文件
uv lock
# 只升级某个包
uv lock --upgrade-package requests
uv.lock 文件锁定了所有依赖(包括间接依赖)的精确版本,确保团队每个人和生产环境用的完全一致。这和 package-lock.json(Node.js)、Cargo.lock(Rust)是一个思路。
uv 管理 Python 版本
uv 还能替代 pyenv,帮你安装和管理 Python 本身:
bash
# 安装 Python
uv python install 3.12
uv python install 3.11 3.10 # 一次装多个
# 查看已安装的版本
uv python list
# 固定项目的 Python 版本
uv python pin 3.12
uv python pin 会在项目目录下创建 .python-version 文件,之后在这个目录下执行 uv 命令都会用指定的 Python 版本。
uv 的 tool 命令
这个功能挺有意思------你可以用 uv 安装"命令行工具"类型的 Python 包,类似 pipx:
bash
# 安装全局工具
uv tool install ruff
uv tool install black
uv tool install httpie
# 直接运行,不安装(类似 npx)
uvx ruff check .
uvx black --check .
uvx cowsay "hello"
uvx 是 uv tool run 的简写。它会在临时环境里运行这个工具,用完就走,不污染你的系统。偶尔用一次的工具特别合适,比如 uvx cookiecutter 生成项目模板。
uv 的脚本支持
uv 还有个很酷的用法------直接在 Python 脚本里声明依赖:
python
# /// script
# requires-python = ">=3.12"
# dependencies = [
# "requests",
# "rich",
# ]
# ///
import requests
from rich import print
response = requests.get("https://httpbin.org/json")
print(response.json())
然后用 uv run 执行:
bash
uv run my_script.py
uv 会自动创建一个临时环境、安装声明的依赖、运行脚本。不需要手动建虚拟环境,不需要 requirements.txt,一个文件搞定一切。
写一次性脚本、分享代码片段的时候,这个功能简直太方便了。
从现有项目迁移到 uv
如果你有一个用 requirements.txt 管理依赖的老项目,迁移很简单:
bash
# 1. 创建虚拟环境
uv venv
# 2. 安装现有依赖
uv pip install -r requirements.txt
# 3.(可选)迁移到 uv 项目管理模式
uv init --bare
uv add flask requests pandas # 把你直接用的包加进来
uv sync
迁移到 pyproject.toml 管理后,你就可以扔掉 requirements.txt 了(或者保留它给不用 uv 的同事用)。
uv 和 Conda 的关系
uv 目前专注于纯 Python 包的管理。如果你的项目依赖 CUDA、C 库这些非 Python 的东西(比如深度学习),Conda 仍然是更好的选择。
简单说:
- 纯 Python 开发(Web、爬虫、自动化脚本)→ uv 完全够用
- 数据科学 / 机器学习(依赖 CUDA、MKL、HDF5 等)→ Conda 还是首选
但随着 uv 的发展,未来可能也会支持这些。
uv 的现状和未来
uv 还在快速迭代中(写这篇文章的时候版本是 0.7.x),但已经很稳定了。很多公司已经在生产环境使用,包括 Vercel、Dagster 等。
如果你现在还在用 pip + venv + requirements.txt 的组合,强烈建议试试 uv。迁移成本很低,收益很大。
面试题
1. uv 为什么比 pip 快这么多?
三个主要原因:一是用 Rust 编写,没有 Python 解释器的启动和运行开销;二是使用全局缓存,同一个包只下载和解压一次;三是并行处理下载和安装任务。此外,uv 的依赖解析算法也经过优化,避免了 pip 在复杂依赖树下的回溯开销。
2. uv.lock 文件的作用是什么?为什么要提交到 Git?
uv.lock锁定了所有依赖的精确版本,包括间接依赖。提交到 Git 可以确保团队所有成员和 CI/CD 环境使用完全一致的依赖版本,避免"我这里能跑你那里不行"的问题。这和 Node.js 的 package-lock.json 是一个道理。
3. uvx 命令和 uv tool install 有什么区别?分别适用什么场景?
uv tool install会把工具持久安装到全局,之后可以直接使用,适合经常用的工具(如 ruff、black)。uvx(等同于uv tool run)在临时环境中运行工具,不安装到本地,适合偶尔使用的工具(如 cookiecutter),用完不留痕迹。
4. uv 能完全替代 Conda 吗?为什么?
目前不能完全替代。uv 专注于 Python 包和项目管理,处理纯 Python 依赖非常出色。但 Conda 能管理非 Python 的系统级依赖(如 CUDA、C 库、HDF5 等),这在数据科学和机器学习领域很关键。如果你的项目依赖这些非 Python 组件,Conda 仍然是更好的选择。