uv :新一代的 Python 包管理工具

发布: 2025-08-03   上次更新: 2025-08-03   分类: 效率工具   标签: uv python

文章目录

今天我想介绍一个新的 Python 包管理工具:uv。它是一个采用 Rust 写的包管理器,旨在提供更快、更可靠的包管理体验:

说实话,作为一个不是靠 Python 吃饭的程序员,每次写 Python 我的心情都挺复杂的,一方面是因为 Python 的语法和生态都很棒,我能够很快写出满足需求的脚本;另一方面是因为 Python 的包管理工具实在太糟糕了,每次稍微大型的 Python 项目,我都要去搜索一下最佳实践是什么,该用哪个 lsp、formatter,以及怎么管理虚拟环境难等一堆问题。

uv 的出现让我看到了希望,它的设计理念是简化 Python 的包管理流程,提供一个统一的工具来处理所有的包管理任务。

管理多个 Python 版本

Python 的演进很奇怪,每个版本之间的差异都很大,导致很多时候需要特定版本的 Python 才能运行某些包或项目。因此多版本管理是个刚需,通过 uv,我们可以通过简单的命令来安装和切换不同的 Python 版本。

1
2
3
4
5
6
7
# 默认安装在 ~/.local/share/uv/python/ 目录下
uv python install 3.12.4
# pin 命令会在当前目录内创建 .python-version 文件,记录当前使用的 Python 版本
uv python pin 3.12.4

uv python list
uv python uninstall 3.12.4

管理虚拟环境

为了保证项目的依赖隔离,Python 社区推荐使用虚拟环境来管理项目的依赖。在 uv 之前,我们需要手动创建并激活,下面是一个典型的工作流:

1
2
3
4
5
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# 退出虚拟环境
deactivate

uv 的理念与此不同,它默认就会为每个项目创建一个虚拟环境,并且在安装依赖时自动激活这个虚拟环境。这样我们就不需要手动管理虚拟环境了。

项目结构

虚拟环境往往是和一个项目绑定的, uv init 就会创建一个如下目录结构的项目:

.
├──.gitignore
├──.python-version
├──README.md
├──main.py
├──pyproject.toml

在我们后续执行 uv add 命令安装依赖时,uv 会自动在当前目录下创建一个虚拟环境,并且后续所有 uv 的命令(比如 uv run uv sync )都会使用这个虚拟环境。这样我们就可以直接使用 uv 来管理项目的依赖,而不需要手动创建和激活虚拟环境。一个完整的项目是这样的:

.
├── .venv
│   ├── bin
│   ├── lib
│   └── pyvenv.cfg
├── .python-version
├── README.md
├── main.py
├── pyproject.toml
└── uv.lock

pyproject.toml

pyproject.toml 是 Python 的标准配置文件,用于描述项目的元数据和依赖关系。uv 会自动生成这个文件,并且在我们添加依赖时会更新它:

1
2
3
4
5
6
[project]
name = "hello-world"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
dependencies = []

与 uv 相关的配置项会被放在 [tool.uv] 部分,一般情况下不需要配置。更多可参考:Configuration files | uv

uv.lock

uv.lock 是 uv 的锁文件,用于记录当前项目的依赖关系和版本信息。它类似于 npm 的 package-lock.json 或者 yarn.lock 文件。uv.lock 文件会在我们添加或更新依赖时自动生成和更新。

管理依赖

uv 提供了一个统一的命令来管理依赖,类似于 npm 的 install 命令。我们可以使用 uv add 命令来添加依赖,或者使用 uv remove 命令来删除依赖,uv 会自动更新 pyproject.toml 和 uv.lock 文件。

1
2
3
4
5
6
7
8
uv add requests
uv remove requests

# Specify a version constraint
uv add 'requests==2.31.0'

# Add a git dependency
uv add git+https://github.com/psf/requests

如果之前项目有 requirements.txt 文件,可以通过下面命令导入 pyproject.toml:

1
uv add -r requirements.txt

如果手动修改了 pyproject.toml 文件,uv 会自动检测到变更并更新 uv.lock 文件。我们也可以使用 uv sync 命令来同步依赖,这会根据 pyproject.toml 文件安装或更新依赖。更多可以参考:Managing dependencies

运行项目

uv 提供了一个统一的命令来运行项目,类似于 npm 的 start 命令。我们可以使用 uv run 命令来运行项目,uv 会自动激活虚拟环境并执行指定的 Python 文件。

1
2
uv add flask
uv run -- flask run -p 3000

我们也可以使用 uv run 命令来运行任意的 Python 文件,比如:

1
2
3
4
# main.py
import flask

print("hello world")
1
uv run main.py

当然,我们也可以手动激活虚拟环境,然后运行 Python 文件,这和之前的方式是一样的:

1
2
3
uv sync
source .venv/bin/activate
python main.py

执行脚本

PEP 723 中定义了内联脚本元信息(inline script metadata),我们可以直接通过在一个 Python 文件中添加特殊注释来定义脚本的元信息,比如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# /// script
# dependencies = [
#   "httpx",
# ]
# ///

import httpx

resp = httpx.get("https://peps.python.org/api/peps.json")
data = resp.json()
print([(k, v["title"]) for k, v in data.items()][:10])

然后我们可以使用 uv run 命令来运行这个脚本,uv 会自动创建虚拟环境、安装依赖并执行脚本。

我们可以通过如下命令来向一个脚本添加依赖:

1
uv add --script example.py 'requests<3' 'rich'

最后,我们可以将这个脚本打包成一个可执行文件,方便分发和运行:

1
2
3
#!/usr/bin/env -S uv run --script

print("Hello, world!")

假设这个脚本名为: greet ,并且有执行权限,我们可以直接运行它:

1
2
./greet
# Hello, world!

更多用法,可以参考:https://docs.astral.sh/uv/guides/scripts/

tool

许多 Python 包提供了可以作为工具使用的应用程序。uv 具有专门的支持,便于调用和安装工具。比如:

1
2
3
4
uv tool run ruff

# uvx 就是 uv tool run 的别名
uvx ruff

uv 在自动创建一个隔离的虚拟环境来运行工具,这样就可以避免工具之间的冲突。

如果一个工具经常使用,最好将其安装到持久环境中,并将其添加到 PATH 中( ~/.local/bin ),而不是反复调用 uvx。

我们可以使用 uv tool install 命令来安装工具,或者使用 uv tool uninstall 命令来删除工具。与 pip install 不同的是,安装工具并不会使其模块在当前环境中可用。例如,以下命令将失败:

1
python -c "import ruff"

这种隔离对于减少工具、脚本和项目依赖关系之间的相互作用和冲突至关重要。

总结

毫无疑问,uv 是一个非常有前途的 Python 包管理工具,它的设计理念和功能都很符合现代开发的需求。它简化了 Python 的包管理流程,提供了一个统一的工具来处理所有的包管理任务。

再加上 Rust 的性能优势,uv 在速度和可靠性上都表现得非常出色。对于所有需要写 Python 的开发者来说,uv 是一个值得尝试的工具。

评论

欢迎读者通过邮件与我交流,也可以在 MastodonTwitter 上关注我。