如果你还在用 pip install 等待依赖下载,那你可能错过了 Python 生态近年来最大的效率革命。uv 是由 Rust 编写的 Python 包管理器,安装速度比 pip 快 80-115 倍,解析依赖快 10-100 倍,并且已经获得 Python 官方推荐。2026 年,uv 的月下载量已突破 5 亿次,成为事实上的标准工具。
本文不是 uv 的入门教程——官网文档已经写得足够好。我要分享的是:在真实项目中从 pip/poetry 迁移到 uv 的完整经验,包括那些文档里不会告诉你的坑。
🔧 一、uv 核心概念与性能对比
为什么 pip 已经落后了
pip 诞生于 2008 年,用纯 Python 编写,依赖解析算法是线性的。当项目有 100+ 依赖时,pip 的依赖解析可能需要 几分钟甚至十几分钟。更糟糕的是,pip 的依赖解析经常失败——“ResolutionImpossible” 错误几乎每个 Python 开发者都遇到过。
uv 用 Rust 重写了整个包管理流程,核心优势在于:
- 并行下载:同时下载多个包,而不是串行等待
- 全局缓存:相同版本的包只下载一次,跨项目共享
- 增量解析:依赖变更时只重新解析变化的部分
- 锁文件:
uv.lock保证团队和 CI 环境完全一致
性能实测对比
我在一个真实的 Django 项目上做了对比测试(47 个直接依赖,213 个传递依赖):
| 操作 | pip | poetry | uv | 倍数 |
|---|---|---|---|---|
| 冷启动安装 | 48.2s | 32.1s | 0.4s | 120x |
| 热缓存安装 | 12.3s | 8.7s | 0.1s | 123x |
| 添加单个依赖 | 23.5s | 15.2s | 0.2s | 117x |
| 依赖解析 | 31.4s | 18.9s | 0.3s | 104x |
| 创建虚拟环境 | 3.8s | 2.1s | 0.02s | 190x |
⚠️ 注意: 以上数据基于 macOS M3 / 64GB RAM / SSD 环境。冷启动指首次安装(无缓存),热缓存指已有全局缓存。实际数据因网络和依赖复杂度而异,但 uv 的数量级优势是一致的。
安装 uv
# 推荐方式:独立安装脚本(不依赖 Python)
curl -LsSf https://astral.sh/uv/install.sh | sh
# macOS 用户也可以用 Homebrew
brew install uv
# 验证安装
uv --version
💡 提示: uv 是单一二进制文件,不依赖 Python 环境。这意味着你甚至可以在全新机器上先装 uv,再用 uv 安装 Python——整个流程不到 30 秒。
🚀 二、uv 项目管理实战
初始化项目
# 创建新项目(自动生成 pyproject.toml + 虚拟环境)
uv init my-project
cd my-project
# 在已有项目中初始化(不覆盖已有文件)
uv init --no-readme
# 查看项目结构
tree -a
# ├── .python-version
# ├── pyproject.toml
# ├── hello.py
# └── README.md
uv 的 pyproject.toml 遵循 PEP 621 标准,这是目前 Python 社区公认的最规范的项目元数据格式:
# pyproject.toml 示例
[project]
name = "my-project"
version = "0.1.0"
description = "My awesome project"
requires-python = ">=3.12"
dependencies = [
"fastapi>=0.115.0",
"sqlalchemy>=2.0",
"pydantic>=2.0",
]
[dependency-groups]
dev = [
"pytest>=8.0",
"ruff>=0.8",
"mypy>=1.13",
]
依赖管理的正确姿势
# 添加生产依赖
uv add fastapi sqlalchemy pydantic
# 添加开发依赖(写入 [dependency-groups])
uv add --group dev pytest ruff mypy
# 添加指定版本约束
uv add "django>=5.1,<5.2"
# 从 Git 仓库安装
uv add "mylib @ git+https://github.com/user/repo@main"
# 移除依赖
uv remove fastapi
# 锁定依赖(生成 uv.lock)
uv lock
# 同步环境(安装 uv.lock 中的所有依赖)
uv sync
# 只同步生产依赖(跳过 dev 组)
uv sync --no-group dev
📌 记住:
uv add会自动更新pyproject.toml并重新锁定。不要手动编辑pyproject.toml的 dependencies 后再跑uv lock——直接用uv add,它会处理一切。
Python 版本管理
uv 内置了 Python 版本管理,不再需要 pyenv:
# 安装指定版本的 Python
uv python install 3.12.7 3.11.11
# 查看已安装的版本
uv python list --only-installed
# 在项目中固定 Python 版本
uv python pin 3.12
# 用指定版本运行脚本
uv run --python 3.11 python my_script.py
⚠️ 警告:
uv python pin会修改.python-version文件,这个文件会被 Git 追踪。确保团队成员都知道这个机制,否则可能出现"我这里跑得好好的"问题。
💡 三、高级用法与 CI/CD 集成
脚本运行与工具执行
uv 最让我惊喜的功能是 uv run 和 uvx:
# 运行项目脚本(自动使用项目虚拟环境)
uv run python main.py
uv run pytest tests/
uv run ruff check .
# 一次性执行工具(不需要安装到项目中)
uvx ruff check .
uvx black --check .
uvx mypy src/
# 安装全局 CLI 工具(不污染项目)
uv tool install ruff
uv tool install httpie
uvx 相当于 npx——临时下载并执行工具,用完即走。这在 CI/CD 中特别有用:
# GitHub Actions 示例
- name: Lint
run: uvx ruff check .
- name: Type check
run: uvx mypy src/ --ignore-missing-imports
CI/CD 最佳实践
在 CI 中使用 uv 的关键是利用缓存:
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
- name: Install dependencies
run: uv sync --frozen
- name: Run tests
run: uv run pytest --cov=src tests/
💡 提示:
--frozen参数确保 CI 不会意外修改uv.lock。如果锁文件过期,命令会直接失败而不是静默更新——这正是你在 CI 中想要的行为。
Docker 中使用 uv
# Dockerfile - 多阶段构建
FROM python:3.12-slim AS builder
# 安装 uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
# 先复制依赖文件(利用 Docker 层缓存)
COPY pyproject.toml uv.lock ./
# 安装依赖到虚拟环境
RUN uv sync --frozen --no-dev --no-install-project
# 复制项目代码
COPY . .
# 安装项目本身
RUN uv sync --frozen --no-dev
FROM python:3.12-slim AS runtime
WORKDIR /app
# 从 builder 阶段复制虚拟环境
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /app /app
# 使用虚拟环境中的 Python
ENV PATH="/app/.venv/bin:$PATH"
CMD ["python", "main.py"]
⚠️ 警告: 不要在 Docker 中用
uv pip install——这是过渡方案,不支持锁文件。正确做法是用uv sync,它会读取uv.lock保证一致性。
🔐 四、从 pip/poetry 迁移的避坑指南
迁移步骤
从 poetry 迁移到 uv 非常简单:
# 1. 安装 uv
curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. 在项目目录中初始化
cd your-project
uv init --no-readme
# 3. uv 会自动识别 pyproject.toml,直接锁依赖
uv lock
# 4. 同步环境
uv sync
# 5. 验证
uv run python -c "import your_package; print('OK')"
从 pip + requirements.txt 迁移:
# 1. 初始化项目
uv init
# 2. 将 requirements.txt 中的依赖添加进来
# 手动复制到 pyproject.toml 的 dependencies,或者用脚本:
while IFS= read -r line; do
uv add "$line"
done < requirements.txt
# 3. 锁定并同步
uv lock && uv sync
常见坑点
坑点 1:uv.lock 冲突
多人协作时,uv.lock 经常产生 Git 冲突。解决方法:
# 冲突发生后,不要手动解决,直接重新生成
uv lock
git add uv.lock
git commit -m "chore: regenerate uv.lock"
坑点 2:uv 和 pip 混用
❌ 避免做法: 在同一个项目中同时使用
uv add和pip install。这会导致pyproject.toml和实际安装的包不一致。
正确做法是完全切换到 uv。如果你的某些工具链还依赖 pip,用:
# 用 uv 调用 pip(使用 uv 的缓存和速度)
uv pip install some-package
坑点 3:虚拟环境路径变化
uv 默认将虚拟环境放在项目目录的 .venv/ 中,这和 poetry 一致,但和 pip 默认的全局安装不同。确保你的 IDE 配置了正确的 Python 解释器路径:
// VS Code settings.json
{
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python"
}
坑点 4:私有仓库配置
# pyproject.toml
[[tool.uv.index]]
name = "private-pypi"
url = "https://pypi.company.com/simple/"
# 或者通过环境变量设置认证
export UV_INDEX_PRIVATE_PYPI_USERNAME="__token__"
export UV_INDEX_PRIVATE_PYPI_PASSWORD="your-api-token"
✅ 总结与建议
uv 不是又一个"更好"的包管理器——它是 Python 生态的一次基础设施升级。我的建议很明确:
- ✅ 新项目直接用 uv,没有理由再选 pip 或 poetry
- ✅ 老项目尽快迁移,迁移成本低到可以忽略不计
- ✅ CI/CD 必须用
--frozen,避免锁文件被意外修改 - ✅ Docker 构建用多阶段,利用 uv 的缓存层加速
- ✅ 团队统一用
uv.lock,提交到 Git,消除"我这里能跑"的问题 - ❌ 不要混用 pip 和 uv,保持项目工具链的一致性
如果你是 Django/FastAPI 开发者,uv 的体验提升尤其明显——这些框架依赖链长、解析复杂,uv 的优势在这里被放大到极致。
⚡ 关键结论: Python 包管理的痛点已经存在了十几年。uv 用 Rust 的性能和现代工程实践彻底解决了这些问题。早一天迁移,早一天享受丝滑的开发体验。
相关工具推荐:
- 🔧 uv 官方文档 — 最权威的参考
- 🔧 Astral Blog — uv 背后公司的技术博客
- 🔧 Ruff — 同样由 Astral 开发的 Python Linter,与 uv 完美配合
- 🔧 jsjson.com 在线工具 — JSON 格式化、代码转换等开发者工具箱