Python管理工具uv简易教程

1 什么是uv?

1.1 uv诞生的背景

Python 语言因其灵活性和庞大的生态系统而广受欢迎。然而,长期以来,Python 的依赖管理和环境管理一直是开发者们讨论和面临挑战的领域。从 pipvirtualenv/venv,再到后来的 pip-toolsPoetryPDM 等,社区一直在寻求更高效、更可靠的解决方案。

在这场持续的探索中,一个引人注目的新工具出现了—— **uv**。由著名的 Pydantic 和 Rye 工具的创建者 Astral 团队开发,uv 以其惊人的速度和对现有工作流程的兼容性,迅速获得了关注。

本文将带你深入了解 uv 是什么,它能做什么,为什么你可能想尝试它,以及如何开始使用它。

1.2 uv的优势

简单来说,uv 是一个用 Rust 编写的现代 Python 打包工具。它的核心目标是极速地替代 pippip-toolsvenv 等工具的功能。

它之所以特别,主要有以下几个原因:

  1. 极致的速度: 这是 uv 最引以为傲的特性。由于使用 Rust 编写并进行了大量的性能优化,uv 在依赖解析、下载、安装和环境创建等方面比传统的 Python 工具快几个数量级。无论是处理小型项目还是拥有数百个依赖的大型项目,uv 都能提供几乎即时的反馈。
  2. 单一的可执行文件: uv 打包成一个独立的二进制文件,安装简单方便,没有额外的依赖项。这避免了“用什么来安装包管理器”的依赖套娃问题。
  3. 兼容性强: uv 的设计哲学之一是兼容现有的 Python 生态系统。它理解并支持标准的 requirements.txt 文件格式,并采用了类似于 pip-tools.in.txt(锁定文件)的工作流,这意味着许多现有项目可以非常容易地迁移到 uv
  4. 统一工具: uv 旨在将虚拟环境管理(venv)、依赖安装(pip install)、依赖解析和锁定(pip-tools compile)以及环境同步(pip-tools sync)等功能集成到一个工具中,简化开发者的工具链。
  5. 可靠的依赖解析: uv 使用了一个全新的依赖解析器,它被设计得更加健壮和可靠,能够更准确地找到兼容的依赖版本组合,减少版本冲突问题。

可以把 uv 看作是 Python 包管理领域的一辆“跑车”,它专注于将最核心、最频繁的操作(创建环境、安装依赖、管理依赖版本)做到极致的快和稳。

1.3 uv 能替代哪些工具?

uv 目前主要针对以下工具的功能进行替代:

  • venv / virtualenv: 用于创建和管理独立的 Python 虚拟环境。
  • pip install / pip uninstall / pip list: 用于安装、卸载和查看包。
  • pip-compile / pip-sync (来自 pip-tools): 用于从抽象的依赖列表 (requirements.in) 生成精确锁定的依赖列表 (requirements.txt),并根据锁定文件同步环境。

值得注意的是,uv 不是一个完整的项目管理器,它目前不处理发布包、运行脚本、管理项目元数据(如 pyproject.toml 中的 [project] 部分)等功能。这些是 PoetryPDM 等工具的长处。uv 更专注于底层的依赖和环境操作,并且可以作为其他高级工具(比如 Rye 就内置使用了 uv)的后端引擎。

2 安装 uv

安装 uv 非常简单,因为它是一个独立的二进制文件。推荐使用以下方法之一:

方法 1:使用 curl (推荐)

这是最直接的方式,它会下载适用于你操作系统的 uv 可执行文件并将其放置在用户可执行路径中。

在 Linux 或 macOS 上:

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

在 Windows 上,可以使用 PowerShell:

1
irm https://astral.sh/uv/install.ps1 | iex

方法 2:使用 pipx

如果你已经安装了 pipx(一个用于安装和运行 Python 应用程序的工具),你也可以用它来安装 uv

1
pipx install uv

安装完成后,打开新的终端窗口或运行 source ~/.profile (或其他 shell 配置文件) 使 uv 命令生效。你可以通过运行 uv --version 来验证安装是否成功。

1
2
uv --version
# 输出类似 uv 0.1.x

3 uv 的核心工作流与常用命令

uv 采用了一个清晰的工作流,尤其擅长处理基于 requirements.inrequirements.txt 的项目。以下是 uv 的核心命令和它们的作用:

3.1 创建虚拟环境:uv venv

在开始安装包之前,通常需要创建一个独立的 Python 环境,以避免项目之间的依赖冲突。uv venv 命令用于此目的。

1
uv venv

这个命令会在当前目录下创建一个名为 .venv 的文件夹(这是社区推荐的虚拟环境名称),并在其中设置一个新的 Python 环境。

详细解释:
uv venv 会查找系统中可用的 Python 解释器,并复制或创建指向必要文件的链接,构建一个隔离的环境。在这个环境中安装的包不会影响到系统全局或其他项目的 Python 环境。与 python -m venv 相比,uv venv 通常快很多,尤其是在创建大量虚拟环境时。

除了在当前目录创建默认的 .venv 环境外,uv venv 还提供了更灵活的选项:

  • 指定虚拟环境的名称或路径: 你可以在命令后面加上一个路径,来指定虚拟环境的创建位置和名称。这允许你在项目的不同位置创建环境,或者给环境一个自定义的名字。

    1
    2
    3
    4
    5
    # 在当前目录下创建一个名为 my-project-env 的虚拟环境
    uv venv my-project-env

    # 在指定的路径下创建一个虚拟环境 (例如,在用户主目录下的 .venvs 文件夹中)
    uv venv ~/.venvs/another-env
  • 指定 Python 版本: 如果你的系统中安装了多个 Python 版本,并且你希望为这个虚拟环境指定一个特定的 Python 版本(例如 Python 3.9),你可以使用 --python 选项。uv 会在你的系统环境中查找符合指定版本要求的 Python 解释器来创建环境。

    1
    2
    3
    4
    5
    # 使用系统中的 Python 3.9 创建虚拟环境 (uv 会尝试查找 python3.9, python3 等)
    uv venv --python 3.9 .venv

    # 同时指定环境名称和 Python 版本
    uv venv my-env --python 3.10

    uv 在查找 Python 解释器时非常智能,你可以指定主版本号 (3.9),也可以指定次版本号 (3.9.10),甚至可以使用可执行文件的名称 (python3.9)。

激活环境:
创建环境后,你需要激活它才能使用其中安装的包。激活环境的方式取决于你使用的 shell:

  • Bash/Zsh: source .venv/bin/activate
  • Fish: source .venv/bin/activate.fish
  • Nushell: source .venv/bin/activate.nu
  • PowerShell: . .venv\Scripts\Activate.ps1
  • Cmd: .venv\Scripts\activate.bat

激活环境后,你的终端提示符前通常会显示环境的名称(如 (.venv)),并且此时运行 pythonpip 等命令时,使用的是虚拟环境中的版本。

3.2 兼容 pip 的常用命令 (uv pip)

uv 的一个设计目标是与 pip 的常用命令行接口保持兼容性,让用户能够快速上手。大多数你习惯使用的 pip 命令,都可以在 uv pip 下找到对应的功能,并且通常速度更快。

以下是一些常用的 uv pip 命令及其说明:

  • 安装依赖:uv pip install

    这是最常用的命令,用于安装一个或多个 Python 包到当前激活的环境中。你可以指定包的名称,也可以指定特定的版本或版本范围。uv pip install 会负责解析依赖关系并安装所有必需的包。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 安装一个包
    uv pip install requests

    # 安装多个包
    uv pip install requests flask

    # 安装指定版本的包
    uv pip install "requests==2.28.1"

    # 安装一个包的最新兼容版本
    uv pip install "requests>=2.20,<3.0"

    # 从 requirements 文件安装 (同 3.3 节内容,但此处作为兼容 pip 的用法提及)
    uv pip install -r requirements.txt

    详细解释:
    uv pip install 会在当前的虚拟环境(如果已激活)或全局环境中(如果不使用虚拟环境,但通常不推荐)查找、下载并安装指定的包及其依赖。uv 的依赖解析器会负责找出所有包之间兼容的版本组合。它的速度优势在这里体现得淋𝓮无论是安装单个包还是从 requirements 文件批量安装,uv 都比 pip 快很多。

  • 卸载包:uv pip uninstall

    用于从当前环境中移除一个或多个已安装的包。

    1
    uv pip uninstall requests flask

    详细解释:
    uv pip uninstall 会从当前激活的虚拟环境中移除指定的包。需要注意的是,手动卸载包后,你的虚拟环境可能就不再与 requirements.txt 文件精确同步了。通常更推荐的工作流是修改 requirements.in 文件(删除你不再需要的顶级依赖),然后重新运行 uv pip compile 更新 requirements.txt,最后运行 uv pip sync 来清理环境,以保持环境与锁定文件的一致。

  • 查看已安装的包:uv pip list

    列出当前环境中已安装的所有包及其版本。这是检查环境状态和已安装依赖的便捷方式。

    1
    uv pip list

    详细解释:
    这个命令提供了当前虚拟环境中所有包的快照,方便你查看安装了哪些包以及它们的具体版本。

  • 查看包的依赖树:uv pip tree

    显示当前环境中已安装包的依赖关系树。这有助于理解为什么某个包会被安装以及包之间的相互依赖关系。

    1
    uv pip tree

    详细解释:
    当你项目的依赖比较复杂时,uv pip tree 可以帮助你理解依赖的来源(它是哪个顶级依赖的子依赖),以及整个依赖图。这对于调试依赖冲突或意外安装的包非常有帮助。

3.3 依赖编译与锁定:uv pip compile

这是 uv(以及 pip-tools)工作流中非常重要的一步,用于生成一个精确锁定项目依赖及其所有子依赖版本的 requirements.txt 文件。这确保了项目的构建和部署在任何地方都能获得完全相同的依赖环境,是实现可重复构建 (Reproducible Builds) 的关键。

你通常会创建一个 requirements.in 文件,其中只包含你项目直接需要的顶级依赖:

1
2
3
4
# requirements.in
requests
flask
pytest

然后运行 uv pip compile

1
uv pip compile requirements.in -o requirements.txt

详细解释:
uv pip compile 会读取 requirements.in 文件中的顶级依赖,然后递归地查找这些依赖所依赖的所有包。它会解析出整个依赖树中每一个包的确切版本,甚至包括它们的哈希值(用于进一步验证)。最后,它将这个完整的、精确锁定的依赖列表写入 requirements.txt 文件。

生成的 requirements.txt 文件看起来会像这样(内容会多很多,包含所有间接依赖):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# This file is autogenerated by uv
# Becomes: requirements.in

anyio==3.7.1 \
--hash=sha256:f0d8f...
certifi==2023.11.17 \
--hash=sha256:6f8f7...
charset-normalizer==3.3.2 \
--hash=sha256:a34d1...
click==8.1.7 \
--hash=sha256:1c80c...
# ... 很多很多行 ...
requests==2.31.0 \
--hash=sha256:79127...
sniffio==1.3.0 \
--hash=sha256:c7364...
Werkzeug==3.0.1 \
--hash=sha256:3d45f...

有了这个 requirements.txt 文件,任何人在任何机器上使用 uv pip sync 都可以安装到与你开发时完全相同的依赖环境。

常见选项:

  • -o <output_file>: 指定输出的锁定文件(通常是 requirements.txt)。
  • --upgrade-package <package>: 在编译时升级指定的包到最新兼容版本,即使它已经在 .txt 文件中被锁定。这在你只想升级某个特定依赖时很有用。
  • --no-header: 不在输出文件顶部添加自动生成的注释。

3.4 同步环境:uv pip sync

uv pip sync 的作用是让当前活动的虚拟环境的状态与一个或多个精确锁定的 requirements.txt 文件完全一致

1
uv pip sync requirements.txt

详细解释:
运行 uv pip sync 后,uv 会读取 requirements.txt 文件中列出的所有包和它们的精确版本。然后,它会检查当前虚拟环境中实际安装了哪些包。

  • 如果锁定文件中有的包,但环境中没有,uv 会安装它。
  • 如果锁定文件中有的包,环境中也有,但版本或哈希不匹配,uv 会重新安装正确版本的包。
  • 如果环境中有包,但锁定文件中没有(这意味着这个包不是项目需要的依赖),uv卸载它。

这个过程确保了虚拟环境的内容精确地反映了锁定文件的内容,不多不少,版本完全一致。这对于保证开发、测试和生产环境的一致性至关重要。

uv pip syncuv pip install -r 的区别:
虽然 uv pip install -r requirements.txt 也可以安装锁定文件中的包,但它不会卸载环境中多余的包。uv pip sync 的核心在于实现环境与锁定文件的完全同步,包括删除不需要的包。因此,在团队协作或部署时,uv pip sync 是更推荐的命令,以确保环境的纯净和一致。

3.5 本地项目包管理:uv add

如果你需要管理本地项目依赖,可以使用 uv add 命令。这种情况下, uv会将依赖包安装在项目目录下的虚拟环境中, 而不是添加到全局的Python解释器所在的环境。

本地项目依赖管理

并且通过 uv add <package> 添加依赖时,UV 会自动更新项目的 pyproject.toml 文件,记录包名及版本约束(如 requests>=2.32.3),并生成或更新锁文件 uv.lock,精确锁定所有直接依赖和子依赖的版本。例如:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
uv add requests
```
此操作确保团队协作或部署时,所有环境依赖版本完全一致,避免“在我机器上能运行”的问题。

**开发依赖管理**

支持通过 `--dev` 标志区分开发环境依赖(如测试框架),这些依赖会被记录在 `pyproject.toml` 的 `[dependency-groups]` 部分,例如:
```bash
uv add pytest --dev
```
开发依赖不会影响生产环境的轻量化部署。

**虚拟环境集成**

若项目未初始化虚拟环境,`uv add` 会自动创建 `.venv` 目录并安装依赖,无需手动激活环境。通过 `uv run` 可直接在隔离环境中执行脚本,例如:
```bash
uv run example.py
```
此特性简化了开发流程,尤其适合单文件脚本的依赖管理。


**与`uv pip install` 的区别**

| 特性 | `uv add` | `uv pip install` |
|------------------------|-------------------------------------------|-------------------------------------------|
| 配置文件修改 | 更新 `pyproject.toml` 和 `uv.lock` | 不修改任何配置文件 |
| 依赖解析逻辑 | 主动生成确定性锁文件,确保版本一致性 | 安装当前兼容的最新版本,无版本锁定 |
| 适用场景 | 长期项目管理、团队协作 | 临时测试、全局工具安装 |
| 虚拟环境管理 | 自动创建或同步项目虚拟环境 | 依赖手动激活的现有环境 |
| 性能优化 | 依赖解析速度更快(Rust 实现) | 安装速度提升,但逻辑与传统 pip 对齐 |

**使用建议**
- 优先使用 `uv add`:在需要维护项目依赖声明、锁定版本或协作开发时,应通过 `uv add` 管理依赖,确保环境一致性。
- 选择性使用 `uv pip install`:在临时调试、安装全局工具(如 `ruff`、`black`)或需要兼容现有 `pip` 脚本时使用,避免污染项目配置。
- 混合工作流:例如,使用 `uv pip install` 安装 PyTorch 的 GPU 版本后,可手动将依赖添加到 `pyproject.toml`,再通过 `uv sync` 同步环境。

# 4 结合使用:典型的 uv 工作流

一个使用 `uv` 管理 Python 项目依赖的典型工作流如下:

1. **创建环境:**
```bash
uv venv
source .venv/bin/activate
  1. 定义顶级依赖: 在项目根目录创建 requirements.in 文件,列出你项目直接需要的库。
    1
    2
    3
    4
    5
    # requirements.in
    fastapi
    uvicorn[standard]
    pydantic_settings
    httpx
  2. 编译生成锁定文件: 运行 uv pip compile 生成精确锁定的 requirements.txt
    1
    uv pip compile requirements.in -o requirements.txt
    第一次运行会稍慢一些,因为它需要解析所有依赖并从 PyPI 下载元数据。但比 pip-compile 快得多。
  3. 同步环境: 根据生成的 requirements.txt 安装依赖。
    1
    uv pip sync requirements.txt
    这个步骤通常会非常快,因为它只是按照锁定文件执行安装/卸载操作,无需再次解析。
  4. 开发过程中添加新依赖:
    • 编辑 requirements.in,添加新的顶级依赖。
    • 重新运行 uv pip compile requirements.in -o requirements.txt 更新锁定文件。
    • 重新运行 uv pip sync requirements.txt 将新依赖安装到环境中。
  5. 开发过程中移除依赖:
    • 编辑 requirements.in,移除不再需要的顶级依赖。
    • 重新运行 uv pip compile requirements.in -o requirements.txt 更新锁定文件。
    • 重新运行 uv pip sync requirements.txt 将不再需要的依赖从环境中移除。

这个工作流清晰地分离了“我想要什么”(requirements.in)和“我实际安装了什么”(requirements.txt),并利用 uv 的高速特性,使得依赖管理变得高效且可控。

5 与 pyenv 的结合使用

需要重点说明的是, uv本身并不会直接管理不同Python解释器的版本,而是基于系统已有的 Python 虚拟环境进行管理。因此, 通常我们需要结合其他的Python虚拟环境管理工具来使用。这里最常见的方式就是使用轻量化的 pyenv 。(都用uv了肯定不再用重量级的anaconda了)

这里简单介绍pyenv的使用方法:

5.1 安装与基础配置

Windows
通过 Chocolatey 安装社区维护的 pyenv-win

1
2
choco install pyenv-win -y
refreshenv

Linux/macOS
直接使用原生 pyenv,并确保在 Shell 配置文件(如 .bashrc.zshrc)中添加初始化代码:

1
2
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"

验证安装
运行 pyenv versions 查看已安装的 Python 版本。

5.2 pyenv 的 Python 版本管理

5.2.1 通过 pyenv 安装多版本解释器

例如安装 Python 3.10 和 3.12:

1
2
pyenv install 3.10.11
pyenv install 3.12.0

5.2.2 切换全局或项目本地版本

  • 全局设置:pyenv global 3.12.0
  • 项目本地设置:在项目目录中运行 pyenv local 3.10.11,生成 .python-version 文件。

5.2.3 与 uv 的版本同步

uv 通过读取 .python-versionpyproject.toml 中的 requires-python 字段自动选择解释器版本。例如:

1
uv venv --python 3.10.11  # 显式指定版本创建虚拟环境

6 小节

6.1 为什么选择 uv?与现有工具的对比

uv 并不是第一个 Python 包管理工具,那么它在众多工具中有什么优势呢?

  • vs pip + venv: 这是最基础的组合。uv 将两者的功能整合,提供更快的环境创建和依赖安装速度。更重要的是,uvcompilesync 提供了 pip 本身不具备的强大依赖锁定和环境同步能力,解决了 pip 在可重复构建方面的不足。
  • vs pip-tools: uvpip compilepip sync 直接对标 pip-tools 的同名命令。uv 的主要优势在于压倒性的速度。对于大型项目或在 CI/CD 环境中,uv 可以显著缩短构建时间。此外,uv 是一个单一工具,而 pip-tools 是一个依赖于 pip 和 Python 环境的 Python 包。
  • vs Poetry / PDM: PoetryPDM 是功能更全面的项目管理器。它们使用 pyproject.toml 作为项目配置中心,处理依赖、构建、发布、运行脚本等。uv 目前不涉及这些高级项目管理功能。uv 更专注于底层的依赖解析和安装。对于习惯使用 requirements.txt 工作流或只需要一个快速的 pip/venv/pip-tools 替代品的项目来说,uv 是一个极好的选择。对于追求 All-in-one 项目管理的团队,Poetry 或 PDM 仍然是强有力的竞争者,但未来它们也可能集成 uv 作为其内部的解析和安装引擎,以获得速度提升。
  • vs Rye: Ryeuv 的同门师兄,也是由 Astral 开发的更高级的项目管理器。Rye 专注于简化 Python 工具链的管理(包括 Python 版本本身、虚拟环境、依赖等),并在内部使用了 uv 作为其依赖管理引擎。如果你正在寻找一个全新的、集成的 Python 项目开发环境,Rye 可能更适合你;如果你只想替换现有的 pip/venv/pip-tools 流程,uv 是一个更直接的切入点。

总的来说,uv 的最大亮点在于其无与伦比的速度和对现有标准的良好支持。它是一个高性能的“引擎”,可以作为现有工作流(特别是基于 requirements.txt 的)的直接加速器,或者作为更高级工具(如 Rye)的基础。

6.2 潜在的注意事项和未来展望

uv 是一个相对较新的工具,尽管它已经非常强大和稳定,但仍有一些地方需要注意:

  • 生态系统集成: 虽然 uv 兼容 requirements.txt,但一些依赖于特定 pip 行为或内部结构的工具可能需要时间来完全支持 uv
  • 功能覆盖: 尽管 uv 覆盖了核心的包管理功能,但 pip 有一些更高级或边缘的功能(如通过 VCS 安装、本地目录安装的复杂选项等)uv 可能尚未完全支持或行为略有不同。在使用前最好查阅官方文档确认。
  • 持续发展: uv 正在快速迭代中,新版本可能会带来功能改进或行为变化。

未来,uv 有潜力成为 Python 打包领域的一个基础性工具,其核心的快速解析和安装能力可能会被更广泛地集成到各种 Python 开发工具和平台中。

6.3 总结

uv 是 Python 包管理领域令人兴奋的新进展。它以 Rust 带来的极致速度为核心优势,旨在成为 pipvenvpip-tools 的高性能替代品。通过支持标准的 requirements.txt 文件和类似于 pip-tools 的编译/同步工作流,uv 提供了一条平滑的迁移路径,让开发者能够轻松地获得更快的环境管理和依赖处理体验。

如果你厌倦了等待 pip 解析和安装依赖,或者希望在你的 CI/CD 流程中大幅缩短构建时间,那么 uv 绝对值得你尝试。开始使用 uv venvuv pip install,体验一下“瞬间”完成依赖安装的快感吧!