uv 使用记录:Python 环境、依赖管理与项目运行
一、uv 是什么?
uv 是 Astral 开发的 Python 包和项目管理工具,使用 Rust 编写。它可以安装 Python、创建虚拟环境、安装依赖、记录依赖版本,也可以运行 Python 程序和命令行工具。uv 官方介绍
平时开发 Python 项目,要处理的大致是这几件事:
选择 Python 版本
↓
创建项目的虚拟环境
↓
安装项目依赖
↓
运行代码和测试
↓
保存依赖配置,供其他环境安装
这些操作都可以通过 uv 完成。常用命令分别是 uv python、uv venv、uv add、uv run 和 uv sync。
已经使用 pip + requirements.txt 的项目,也可以先使用 uv pip 安装依赖,保留原来的目录结构。
二、uv 有什么用?
1. 每个项目使用自己的 Python 环境
例如,一个项目需要 Python 3.10,另一个项目使用 Python 3.11,可以分别创建虚拟环境。依赖安装在各自的 .venv 中,运行时选择对应的解释器。
2. 把依赖配置和实际安装版本记录下来
项目需要哪些包,写在 pyproject.toml 中;解析出来的具体版本及依赖关系,记录到 uv.lock。
换电脑或者交给其他人运行时,可以根据这两个文件重新安装环境,减少逐个确认版本的工作。
3. 直接在项目环境中运行命令
在项目目录执行:
uv run python main.py
uv 会准备项目环境,再使用其中的 Python 运行程序。终端里可以省去手动激活环境这一步。
4. 复用下载缓存,管理临时工具
多个项目用到相同依赖时,uv 可以复用缓存。偶尔使用的格式检查工具,还可以通过 uvx 单独运行,工具依赖保存在隔离环境中。
对我这类同时维护业务代码和实验脚本的项目,主要用到的是环境隔离、依赖记录和统一运行命令。安装耗时还会受到网络、缓存和包体积影响,这里没有做安装速度的对比测试。
三、uv 的详细使用
1. 安装 uv
Windows 可以使用官方安装脚本:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
这条命令中的执行策略只作用于启动的 PowerShell 进程。安装完成后重新打开终端,检查命令是否可用:
uv --version
也可以通过已经安装的 Python 安装:
python -m pip install uv
两种方式选择一种即可。后面升级时,跟随原来的安装方式:
# 通过官方独立安装脚本安装
uv self update
# 通过 pip 安装,使用当时安装 uv 的那个 Python
python -m pip install --upgrade uv
Linux、macOS 的官方安装命令是:
curl -LsSf https://astral.sh/uv/install.sh | sh
不同安装方式的路径与升级说明可以查看 uv 安装文档。
2. 安装和查看 Python 版本
查看可用的 Python 版本:
uv python list
只查看已经安装的版本:
uv python list --only-installed
安装项目需要的 Python:
uv python install 3.11
这里指定 3.11,uv 会安装可用的对应补丁版本。如果项目需要固定到某个补丁版本,可以写完整版本号。
查看指定 Python 的位置:
uv python find 3.11
电脑上已经安装的 Python 也可以使用。后面创建环境时,用 --python 指定版本或解释器路径。Python 版本管理
3. 新建一个项目
下面创建一个普通应用项目:
uv init --app --no-package --python 3.11 uv-demo
cd uv-demo
--app 表示应用项目,--no-package 表示暂时按普通脚本组织代码,不配置 Python 包的构建入口。
主要文件如下:
uv-demo/
├── .python-version
├── main.py
├── pyproject.toml
└── README.md
运行一次初始化生成的程序:
uv run python main.py
执行后,项目中会生成 .venv 和 uv.lock。它们各自负责的内容如下:
| 文件或目录 | 作用 |
|---|---|
.python-version |
当前项目选择的 Python 版本 |
pyproject.toml |
项目名称、Python 版本要求、依赖声明和工具配置 |
uv.lock |
解析后的依赖版本、来源等信息 |
.venv/ |
本机实际运行项目的虚拟环境 |
.python-version 和 requires-python 需要配合使用。例如,.python-version 写 3.11,表示当前项目选择 Python 3.11;requires-python = ">=3.11" 表示项目声明支持的 Python 范围。
如果项目实际只支持 Python 3.11,可以根据实际情况将范围收窄为:
requires-python = ">=3.11,<3.12"
这项配置放在 [project] 中。修改范围后重新锁定依赖并运行测试。项目初始化方式和文件结构见 项目使用文档。
4. 添加项目依赖
以 HTTP 客户端 httpx 为例:
uv add httpx
默认情况下,这一步会更新依赖声明、锁文件,并把依赖安装到项目环境中。
也可以指定版本要求:
# 固定到指定版本
uv add "httpx==0.28.1"
# 或者设置允许使用的版本范围
uv add "httpx>=0.28.1,<0.29"
这两条是不同的版本约束写法,按项目需要选择一种。带比较符号时加引号,避免被终端当成其他语法处理。
开发阶段使用的测试和检查工具,可以单独放进开发依赖组:
uv add --dev pytest ruff
pyproject.toml 中的配置大致如下,实际版本以命令生成的内容为准:
[project]
name = "uv-demo"
version = "0.1.0"
requires-python = ">=3.11"
dependencies = [
"httpx>=0.28.1",
]
[dependency-groups]
dev = [
"pytest",
"ruff",
]
删除依赖使用:
uv remove httpx
uv remove --dev ruff
上面两条只是删除命令示例;继续下面的演示时,需要保留刚才添加的包。依赖分组和版本声明见 依赖管理文档。
5. 运行代码和测试
将 main.py 修改为:
import httpx
def get_host(url: str) -> str:
return httpx.URL(url).host
if __name__ == "__main__":
print(get_host("https://example.com/api"))
运行:
uv run python main.py
输出:
example.com
这段代码只解析 URL,不会发起网络请求。
新建 test_main.py:
from main import get_host
def test_get_host():
assert get_host("https://example.com/api") == "example.com"
执行测试和代码检查:
uv run pytest -q
uv run ruff check .
如果项目按模块组织,比如前面的多智能体项目,可以在项目根目录运行:
uv run python -m multi_agent.main --demo
项目模式下,uv run 默认会先检查锁文件和环境,再执行命令。已有项目第一次使用时,要先确认根目录 pyproject.toml 中声明的依赖是否符合当前项目需要。运行命令说明
编辑器也需要选择同一个解释器。Windows 下通常是:
项目目录\.venv\Scripts\python.exe
可以在终端中打印实际解释器路径,再与编辑器配置核对:
uv run python -c "import sys; print(sys.executable)"
6. 锁定版本和同步环境
这几个命令经常放在一起用:
| 命令 | 作用 |
|---|---|
uv lock |
根据项目配置生成或更新锁文件 |
uv lock --check |
检查锁文件是否与项目配置一致 |
uv sync |
根据项目配置和锁文件同步环境,必要时更新锁文件 |
uv sync --locked |
要求锁文件已与配置一致,再同步环境 |
uv sync --frozen |
直接使用已有锁文件,跳过与项目配置的一致性检查 |
日常修改依赖后,可以执行:
uv sync
uv run pytest -q
拉取代码后,或者在持续集成中安装依赖,可以使用:
uv sync --locked
uv run --locked pytest -q
--locked 遇到需要更新锁文件的情况会报错,可以据此发现遗漏提交的依赖变更。
部署时只安装运行依赖:
uv sync --locked --no-dev
uv run --locked --no-dev python main.py
这里没有安装开发依赖,后续运行命令也保持 --no-dev。需要开发工具时,重新执行普通的 uv sync。
另外,uv sync 默认会移除当前同步结果中多余的包。项目长期使用的依赖应通过 uv add 记录下来,便于后续环境同步。锁定与同步说明
7. 更新依赖版本
更新某一个包的锁定版本:
uv lock --upgrade-package httpx
uv sync
uv run pytest -q
更新所有依赖的锁定版本:
uv lock --upgrade
uv sync
uv run pytest -q
升级仍需满足 pyproject.toml 中的版本约束。如果配置固定了 httpx==0.28.1,需要先调整这项约束,再进行版本升级。
更新完成后查看 pyproject.toml 和 uv.lock 的变化,再提交到仓库。长期维护的项目可以按包逐个升级,出现问题时也方便定位对应变更。
8. 在旧项目中使用 uv
已有项目通常会遇到两种情况。
继续使用 requirements.txt:
在旧项目根目录创建环境,然后安装原来的依赖文件:
uv venv --python 3.11
uv pip install --python .venv/Scripts/python.exe -r requirements.txt
.\.venv\Scripts\python.exe main.py
这里显式指定解释器,可以看清依赖安装到哪个环境。
如果项目已经有可用的 .venv,直接执行安装命令即可。uv pip install 负责修改指定环境,项目的 pyproject.toml 和 uv.lock 由项目管理命令维护。
需要手动激活环境时:
.\.venv\Scripts\Activate.ps1
python main.py
deactivate
PowerShell 限制激活脚本执行时,也可以继续使用前面的完整解释器路径运行。虚拟环境使用说明
把依赖交给 uv 项目管理:
对于还没有 pyproject.toml 的旧项目,在根目录执行:
uv init --bare --python 3.11
uv python pin 3.11
uv add -r requirements.txt
uv run python main.py
已经有 pyproject.toml 的项目直接检查并补充现有配置,跳过初始化。
如果旧 requirements.txt 来自整个环境的 pip freeze,里面可能同时包含直接依赖、间接依赖和临时安装的工具。导入前先整理实际需要的包;需要保持原环境版本时,则保留相应的固定版本要求。从 pip 迁移到 uv 项目
9. 导出 requirements.txt
有些部署脚本仍然使用 requirements.txt,可以从锁文件导出:
uv export --locked --no-dev --format requirements.txt --output-file requirements.txt
这份文件来自当前锁定结果,后续依赖变更后重新导出。如果原文件仍在人工维护,可以将输出文件名改为 requirements-export.txt,先核对两份文件的差异。
普通依赖的导出文件可以交给 pip 安装。项目使用自定义包源、CUDA wheel 或本地路径依赖时,还需要把对应安装源、平台要求和文件一起交付。锁文件导出说明
继续维护 requirements 工作流时,也可以区分“直接依赖”和“完整安装列表”:
# requirements.in
httpx>=0.28.1,<0.29
先解析,再同步:
uv pip compile requirements.in --output-file requirements.txt
uv pip sync --python .venv/Scripts/python.exe requirements.txt
uv pip sync 按文件中的完整列表同步环境,会移除多余包。这里应使用解析后包含间接依赖的文件;普通手写依赖列表可以先通过 uv pip install -r 安装。requirements 锁定与同步
10. 配置镜像源和专用安装源
项目需要使用镜像源时,可以在 pyproject.toml 中添加:
[[tool.uv.index]]
name = "aliyun"
url = "https://mirrors.aliyun.com/pypi/simple/"
default = true
default = true 会将它设为默认索引,替换默认的 PyPI 地址。镜像同步进度可能影响新版本是否可用,遇到找不到版本时,可以核对官方 PyPI 与镜像中的发布情况。
只想为某次命令指定默认索引时:
uv pip install httpx --default-index https://pypi.org/simple
uv 的索引配置放在自己的配置文件或命令参数中;原有 pip 配置需要单独确认是否已迁移。索引配置说明
Python AI 项目还经常需要单独配置 PyTorch 下载源。以 CPU 版本为例,在已有配置中合并以下内容:
[[tool.uv.index]]
name = "torch-cpu"
url = "https://download.pytorch.org/whl/cpu"
explicit = true
[tool.uv.sources]
torch = { index = "torch-cpu" }
再添加依赖:
uv add torch
explicit = true 将这个索引留给显式指定的包使用,普通依赖继续使用项目的常规索引。
如果还使用 torchvision、torchaudio,需要核对它们与 torch 的版本配套关系,并按需要添加对应来源。CUDA 项目再选择适合该版本和显卡驱动的安装组合,确认索引中确实提供目标 wheel。配置方式见 uv 与 PyTorch 集成文档。
11. 运行一个带依赖的独立脚本
临时写一个格式转换、接口测试或者数据处理脚本时,可以把依赖记录在脚本本身。
先创建 hello.py:
from rich import print
print("hello uv")
给这个已有脚本声明依赖:
uv add --script hello.py rich
uv 会在文件开头写入脚本依赖信息。然后执行:
uv run hello.py
运行时会根据脚本元数据准备隔离环境。分享这个文件时,依赖说明也保留在文件里。
只临时使用一次依赖,也可以写在运行命令中:
uv run --with rich hello.py
长期复用的脚本可以使用前面的元数据方式保存依赖;需要固定解析结果时,还可以使用 uv lock --script hello.py 生成对应锁文件。独立脚本使用说明
12. 使用 uvx 运行工具
偶尔检查一份代码,可以直接执行:
uvx ruff check .
uvx 是 uv tool run 的简写,工具在隔离环境中运行。需要固定工具版本时,可以使用 工具名@版本号 的形式。
经常使用的工具可以安装为持久工具:
uv tool install ruff
uv tool list
安装后如果终端找不到命令,检查工具可执行目录是否已加入 PATH,必要时执行 uv tool update-shell 后重新打开终端。
项目本身依赖 Ruff 做代码检查时,可以继续使用 uv add --dev ruff 和 uv run ruff check .,这样团队运行的是项目锁定的工具版本。工具运行与安装
13. 查看环境和处理常见问题
查看当前安装的包和依赖关系:
uv pip list --python .venv/Scripts/python.exe
uv pip check --python .venv/Scripts/python.exe
uv tree
uv pip check 检查当前已安装包声明的依赖是否满足;uv tree 查看项目依赖关系。环境检查命令
运行时提示 ModuleNotFoundError:
先确认运行脚本用的是哪个 Python:
uv run python -c "import sys; print(sys.executable)"
再确认项目是否声明了缺失的依赖。项目模式下用 uv add 包名 补充;requirements 模式下检查目标 .venv 的安装结果。
虚拟环境提示 No module named pip:
uv 创建的环境通常不会额外安装 pip。可以直接使用 uv 安装依赖:
uv pip install --python .venv/Scripts/python.exe -r requirements.txt
我的多智能体项目环境中也遇到了这种情况,使用这条命令即可继续管理依赖。
解析依赖时提示 Python 版本不满足:
一起检查 .python-version、pyproject.toml 中的 requires-python,以及依赖包支持的 Python 范围。uv 会按项目声明的兼容范围解析依赖;只修改本机解释器时,项目配置仍可能声明着其他版本。
命令安装成功,但编辑器仍然报找不到包:
将编辑器的项目解释器切换到 .venv/Scripts/python.exe,再重新运行。终端和编辑器使用同一个环境后,才能读取到同一组依赖。
14. 提交哪些文件,以及日常命令速查
普通应用项目提交代码时,一起提交:
pyproject.toml
uv.lock
.python-version
.venv/ 放进 .gitignore。其他人拿到代码后,在兼容的 Python 和系统环境中执行 uv sync --locked,重新安装项目依赖。
日常可以按下面这张表查命令:
| 要做的事 | 命令 |
|---|---|
| 安装 Python 3.11 | uv python install 3.11 |
| 新建普通应用项目 | uv init --app --no-package --python 3.11 项目名 |
| 记录项目 Python 版本 | uv python pin 3.11 |
| 添加运行依赖 | uv add 包名 |
| 添加开发依赖 | uv add --dev 包名 |
| 运行程序 | uv run python main.py |
| 运行测试 | uv run pytest |
| 按已有锁文件安装 | uv sync --locked |
| 更新某个包的锁定版本 | uv lock --upgrade-package 包名 |
| 安装旧项目依赖 | uv pip install -r requirements.txt |
| 执行独立脚本 | uv run 脚本.py |
| 临时使用命令行工具 | uvx 工具名 |
- 本文标签: Python
- 本文链接: https://www.tianyajuanke.top/article/106
- 版权声明: 本文由吴沛芙原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权