UV 工具完整指导教程

写在前面:如果你受够了 Python 包管理的混乱——pip 的慢、Poetry 的卡顿、virtualenv 的繁琐——那么 uv 就是来拯救你的。作为一个用 Rust 写的新工具,它不仅快得离谱(比 pip 快 10-100 倍),而且把 pip、poetry、pipx、pyenv 的活全干了。这篇教程不讲废话,直接带你上手这个改变游戏规则的工具。


1. 为什么是 UV?

简单说:它把 Python 开发中最痛苦的环节变快了,而且统一了。

以前你需要:

  • pyenv 装 Python
  • virtualenv 建环境
  • pip 装包
  • pip-tools 锁版本
  • pipx 跑工具

现在,一个 uv 全部搞定。它支持跨平台的 uv.lock(终于不用担心同事的 Windows 跑不起来了),支持 PEP 735 依赖分组,甚至能帮你管理 Python 版本。

最重要的是:它真的很快。在没有缓存的情况下,它能把几分钟的安装过程压缩到几秒钟。


2. 极速安装

别整那些复杂的,直接上命令。

Windows (PowerShell)

1
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

macOS / Linux

1
curl -LsSf https://astral.sh/uv/install.sh | sh

验证与升级

装完跑一下 uv --version 看看。以后想升级,直接:

1
uv self update

老鸟建议:虽然可以用 pip install uv,但我强烈建议用上面的独立安装脚本。这样 uv 不会依赖于某个具体的 Python 环境,升级也更方便。


3. 两个杀手级功能(必看)

在讲常规项目管理前,先看两个让我爱不释手的功能。

3.1 uvx:临时工具神器

以前想运行 ruffblack 格式化代码,要么装在项目里,要么用 pipx。现在直接用 uvx(或者 uv tool run):

1
2
3
4
5
# 直接运行 ruff,无需安装
uvx ruff check .

# 运行 http 静态服务器
uvx pyhttpd .

它会自动下载最新版、在一个临时隔离环境中运行,用完即走,不污染你的系统。

3.2 单文件脚本依赖 (/// script)

写个小脚本还要建 requirements.txt?太麻烦了。uv 支持 PEP 723 内联元数据。

创建一个 scrape.py

1
2
3
4
5
6
7
8
9
10
11
12
13
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "requests<3",
# "rich",
# ]
# ///

import requests
from rich.pretty import pprint

resp = requests.get("https://httpbin.org/json")
pprint(resp.json())

然后直接跑:

1
uv run scrape.py

uv 会自动创建一个临时环境,装好 requestsrich,跑完脚本。这对于运维脚本、数据抓取小工具简直是神器。


4. 项目初始化与结构

正式做项目时,uv 提供了两种模式。

4.1 应用 vs 库

1
2
3
4
5
# 模式 A:写个应用/脚本/服务
uv init my-app

# 模式 B:写个要发布到 PyPI 的库
uv init --package my-lib
模式 适用场景 结构特点
应用 FastAPI 服务、爬虫、数据分析项目 直接在根目录放 hello.py,不折腾 src 目录
要给别人 pip install 的包 标准 src/ 结构,配置了构建系统

4.2 指定 Python 版本

别再让”我本地是 Python 3.10”这种借口出现了。直接锁死版本:

1
2
# 强制项目使用 Python 3.12
uv python pin 3.12

这会生成一个 .python-version 文件。下次任何人(包括 CI)在这个目录下运行 uv 命令,它都会自动下载并使用 Python 3.12,完全不用手动去官网下安装包。


5. 依赖管理实战

5.1 添加依赖

1
2
3
4
5
6
# 基础操作
uv add requests

# 指定版本和来源
uv add "django>=4.2"
uv add torch --index pytorch=https://download.pytorch.org/whl/cpu

执行 uv add 时,它会自动:

  1. 更新 pyproject.toml
  2. 更新 uv.lock
  3. 同步虚拟环境(这点很爽,不用再手动 pip install 了)

5.2 镜像源配置(国内必读)

国内网络环境你懂的。推荐直接在全局配置里把阿里源加上,一劳永逸。

配置文件位置

  • Windows: %APPDATA%\uv\uv.toml
  • macOS/Linux: ~/.config/uv/uv.toml

内容

1
2
3
4
[[index]]
name = "tuna"
url = "https://mirrors.aliyun.com/pypi/simple/"
default = true # 设为默认,替代 PyPI

这样你所有的项目都会默认走阿里源,速度起飞。


6. 依赖分组 (Dependency Groups)

这是 uv 对比 Poetry 的一大改进,完全遵循 PEP 735 标准。

6.1 为什么需要分组?

不要把 pytestruffmypy 这种开发工具混在生产依赖里。

1
2
3
4
5
# 添加到 dev 分组(默认开发分组)
uv add --dev pytest ruff

# 添加到 docs 分组
uv add --group docs mkdocs

生成的 pyproject.toml 很清晰:

1
2
3
4
5
6
[project]
dependencies = ["fastapi"] # 生产环境只要这个

[dependency-groups]
dev = ["pytest", "ruff"]
docs = ["mkdocs"]

6.2 嵌套分组(高级玩法)

我通常会这样组织,让 dev 组包含其他所有工具,这样开发时只要同步 dev 就全有了:

1
2
3
4
5
6
7
[dependency-groups]
test = ["pytest", "pytest-cov"]
lint = ["ruff", "mypy"]
dev = [
{ include-group = "test" },
{ include-group = "lint" },
]

7. 锁文件与环境同步

uv.lock 是你的定海神针。它跨平台,且包含所有分组的依赖树。

7.1 常用命令

  • uv sync: “让环境变成锁文件的样子”。这是最常用的命令。它会安装缺少的包,卸载多余的包。
  • uv lock --upgrade: 想要升级所有依赖到最新版时用这个。
  • uv run: 在虚拟环境中运行命令。
    1
    2
    3
    # 哪怕你没激活虚拟环境,这样也能跑
    uv run python main.py
    uv run pytest

7.2 生产环境部署

在 Docker 或服务器上,我们通常不需要开发依赖,也不希望 uv 去联网更新锁文件。

1
2
# 仅安装生产依赖,且严格遵守锁文件
uv sync --frozen --no-dev
  • --frozen: 冻结模式。如果环境和锁文件不一致,直接报错,而不是尝试更新锁文件。CI/CD 里必须加这个。
  • --no-dev: 不安装 dependency-groups 里的任何东西。

8. 构建与发布

如果你在写库,uv 也能替代 buildtwine

1
2
3
4
5
# 构建 wheel 和 sdist
uv build

# 发布到 PyPI
uv publish

记得在 pyproject.toml 里配置好 [build-system]。虽然 uv 有自己的后端,但目前 hatchling 依然是兼容性最好的选择之一。

1
2
3
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

9. 工作流集成 (Makefile/CI/Docker)

9.1 Makefile (推荐)

虽然 uv 命令很短,但我还是习惯用 Makefile 封装一下,统一团队认知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.PHONY: install test lint clean

install:
@echo "🚀 Installing dependencies..."
uv sync --all-groups

test:
@echo "🧪 Running tests..."
uv run pytest

lint:
@echo "🔍 Linting code..."
uv run ruff check .
uv run mypy src/

clean:
@echo "🧹 Cleaning up..."
rm -rf .venv dist

9.2 Dockerfile 最佳实践

利用 uv 的多阶段构建可以打出极小的镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 第一阶段:构建环境
FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder
WORKDIR /app

# 先只拷依赖定义,利用 Docker 缓存层
COPY pyproject.toml uv.lock ./
# 安装依赖(不含 dev,不含项目本身)
RUN uv sync --frozen --no-dev --no-install-project

# 再拷代码
COPY . .
# 安装项目本身
RUN uv sync --frozen --no-dev

# 第二阶段:运行时环境
FROM python:3.12-slim-bookworm
WORKDIR /app

# 从 builder 阶段把虚拟环境拷过来
COPY --from=builder /app/.venv /app/.venv
ENV PATH="/app/.venv/bin:$PATH"

COPY src ./src

CMD ["python", "-m", "my_app"]

10. 从 Poetry/Pip 迁移指南

10.1 从 requirements.txt 迁移

这最简单:

1
2
uv init
uv add -r requirements.txt

10.2 从 Poetry 迁移

Poetry 的 pyproject.toml 格式和标准格式(PEP 621)不一样。虽然没有一键转换命令,但手动改也不难:

  1. [tool.poetry.dependencies] 里的内容移到 [dependencies]
  2. ^1.0.0 这种语法改成 >=1.0.0(uv 其实也兼容 ^,但建议用标准写法)。
  3. [tool.poetry.group.dev] 移到 [dependency-groups]下的dev=[]中。

个人经验:迁移是清理技术债的好时机。借这个机会,把那些你都不知道是干嘛的陈年依赖删一删。


总结

uv 不是又一个造轮子的产物,它是 Python 生态期待已久的现代化工具。它快、稳、全。

我的建议

  • 新项目:无脑选 uv
  • 老项目:如果是 requirements.txt 管理的,马上切 uv。如果是 Poetry 管理的,等有空了切 uv

别犹豫了,生命苦短,我用 uv