uv:现代 Python 项目工作流
uv 是 Astral(写 Ruff 那家)用 Rust 写的 Python 工具链,一个二进制替代 pip + venv + pip-tools + pyenv + poetry 的核心功能。2024 年起爆发式普及,到 2026 年已经是多数新项目的默认选择。本文是我切换一年多后的实战笔记。
为什么换
| 痛点 | pip + venv 时代 | uv |
|---|---|---|
| 装依赖慢 | 全量解析 + 串行下载 | 并行下载 + 全局缓存,快一个数量级 |
| 锁定依赖 | 要额外上 pip-tools / pipenv | uv.lock 原生自带 |
| 多版本 Python | pyenv 编译安装 | uv python install 下载预编译,秒装 |
| 工具隔离 | pipx | uv tool / uvx |
最直观的对比:冷启动一个装了几十个依赖的 venv,pip 要一两分钟,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"
项目工作流
初始化
uv init my-project --python 3.12
cd my-project
生成的是标准 pyproject.toml + main.py + .python-version,没有私有格式,随时可以换回任何标准工具链:
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
加依赖(核心用法)
uv add fastapi uvicorn # 加入 dependencies 并安装
uv add --dev pytest ruff # 开发依赖
uv remove uvicorn # 移除
每次 add/remove 都会同步更新 pyproject.toml 和 uv.lock,锁定文件提交进 Git。-lockfile 时代没有"我机器上能跑"。
同步与运行
uv sync # 按 lock 精确还原环境(CI/部署用)
uv run python main.py # 在项目环境里执行,环境不存在会自动建
uv run pytest
uv run 是日常最高频命令——不用手动激活 venv,脚本直接跑。服务器上部署也就两条:
uv sync --frozen # 严格按 lock 安装,不碰 pyproject
uv run gunicorn app:app
单文件脚本
3.9+ 的新玩法,单文件脚本可以直接声明依赖(PEP 723 内联元数据):
# /// script
# requires-python = ">=3.12"
# dependencies = ["httpx"]
# ///
import httpx
print(httpx.get("https://httpbin.org/get").status_code)
uv run fetch.py # 自动装依赖到隔离环境后执行
写运维小脚本、给同事传单文件工具,比"先建 venv 再 pip install"优雅太多。
多版本 Python 管理
uv python list # 看可用版本
uv python install 3.12 3.13t # 装两个:常规 3.12 + free-threaded 3.13
uv python pin 3.12 # 项目锁定 3.12(写入 .python-version)
预编译二进制直接下载,不用像 pyenv 那样本地编译等十分钟。
全局工具
替代 pipx:
uv tool install ruff
uvx ruff check . # 临时运行,等于 pipx run
兼容旧习惯
存量项目不想大改?uv 保留了熟悉的接口:
uv venv # 建 .venv
uv pip install -r requirements.txt # 传统方式装
uv pip freeze > requirements.txt
从 pip 平滑迁移的路径:先 uv venv + uv pip install 尝到速度,再逐步转 uv add 进 pyproject 管理。
踩坑记录
uv sync默认是"精确同步":会卸载不在 lock 里的包。想在环境里临时装点东西调试,用uv pip install,别污染 lock;- 私有源:
UV_INDEX_URL环境变量或 pyproject 里[[tool.uv.index]]配置内部镜像,CI 拉内网包必须配; - Docker 多阶段构建记得利用缓存挂载:
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-dev
COPY . .
CMD ["uv", "run", "gunicorn", "app:app"]
- Windows 下路径带中文/空格的项目偶尔有边缘 bug,注意
UV_CACHE_DIR可指定缓存位置。
总结
一套命令覆盖日常全部场景:
uv init && uv add xxx && uv run xxx # 新项目
uv sync && uv run xxx # 拉下来就跑
uv tool install xxx # 装工具
工具链的意义在于让你忘记它的存在。从 pip 时代"先想想要不要建 venv"到现在"直接 uv run",这就是进步。