uv:一个命令搞定 Python 环境与依赖


预计阅读时间:18 分钟

用过 Python 的人多少都被环境问题折磨过:pip 装包、venv 建虚拟环境、requirements.txt 管依赖,还得手动折腾 Python 版本。项目还没开始写,环境先折腾半天。

uv 是 Astral 公司(就是做 Ruff 的那家)用 Rust 写的 Python 包与项目管理工具,目标是把上面这些环节合并成一条命令。官方宣传语是 "An extremely fast Python package and project manager",官方基准中依赖安装速度通常可达到 pip 的 10~100 倍(具体提升取决于缓存状态和依赖规模)。更重要的是,uv 自己管理 Python 版本——电脑上没装 Python 也能直接开工。

本文基于 uv 0.12.1,覆盖安装、常用命令、日常开发、正式项目、部署和关键文件解读。

安装

Windows

打开 PowerShell,执行一行命令:

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

uv 会被安装到 %USERPROFILE%\.local\bin\uv.exe。安装脚本会自动写入 PATH;如果新开终端仍找不到 uv 命令,把 %USERPROFILE%\.local\bin 手动加进系统环境变量即可。

也可以用包管理器:

winget install --id astral-sh.uv -e
# 或
scoop install main/uv

Linux

在终端执行官方安装脚本:

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

uv 被安装到 ~/.local/bin/uv。如果该目录不在 PATH 里,手动加一下:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

部分发行版或第三方仓库可能提供 uv,但版本通常不如官方安装脚本及时,使用前建议确认具体版本。

验证安装

uv --version

输出版本号即安装成功。uv 的核心项目管理命令在 Windows、Linux 和 macOS 上基本一致,主要区别在于路径格式、Shell 引号和虚拟环境激活命令。以 Windows 和 Linux 为例:

Windows Linux
官方脚本默认安装位置 %USERPROFILE%\.local\bin\uv.exe ~/.local/bin/uv
项目虚拟环境(.venv) .venv\Scripts\python.exe .venv/bin/python

常用命令一览

命令 作用
uv init 新建项目
uv add 包名 添加依赖并安装
uv remove 包名 移除依赖
uv sync 同步项目环境,并按需创建或更新 uv.lock
uv run 命令 在项目虚拟环境中执行命令
uv lock 生成或更新 uv.lock
uv lock --upgrade 升级到约束允许的最新兼容版本
uv python install 版本 安装指定版本 Python
uv python pin 版本 固定项目使用的 Python 版本
uv tree 查看依赖树;加 --outdated 可显示有新版的可升级依赖
uv build 构建发行包(sdist + wheel)
uv publish 发布到 PyPI
uvx 工具名 临时运行 CLI 工具,不全局安装
uv tool install 工具名 全局安装 CLI 工具(类似 pipx)
uv cache clean 清理下载缓存

下面按三个场景展开。

日常开发:个人项目怎么用

从零开始

uv init my-project
cd my-project

从 uv 0.12 开始,uv init 默认创建一个采用 src/ 布局的可打包应用:使用 uv_build 构建后端,并在 pyproject.toml 里声明命令行入口(my-project = "my_project:main"),同时生成 .gitignore.python-version,并顺手 git init。想创建旧式的平铺脚本项目(根目录下 main.py),用 uv init --no-package

添加依赖:

uv add requests        # 运行时依赖
uv add --dev pytest    # 开发依赖(测试、lint 之类)

uv add 会自动创建 .venv 虚拟环境并安装依赖,同时更新 pyproject.tomluv.lock,全程不用手动激活环境。

写代码、跑程序,一律用 uv run

uv run my-project                # 0.12 默认模板自带命令行入口
uv run pytest                     # 跑测试
uv run python -c "import requests; print(requests.__version__)"

(如果用了 --no-package 平铺布局,uv run main.py 一样可以。)

uv run 会自动找到项目根目录的 .venv 并执行命令,不需要激活虚拟环境。想用传统方式激活也可以:

  • Windows PowerShell:.venv\Scripts\Activate.ps1
  • Linux/macOS:source .venv/bin/activate

换机器、clone 别人的项目

拿到项目后只需要:

git clone <仓库地址> && cd 项目目录
uv sync

uv sync 根据 uv.lock 还原项目的默认开发环境(可选依赖组不会默认安装,需要时用 uv sync --extra web--all-extras);如果项目要求的 Python 版本本机没有,uv 会自动下载,什么都不用装。

升级依赖

uv tree --outdated                   # 查看可用的新版本
uv lock --upgrade                    # 升级到约束允许的最新兼容版本
uv lock --upgrade-package requests   # 只升级指定依赖

单文件脚本也可以

不想建项目、只想跑个一次性脚本?uv 支持 PEP 723,在文件头部声明依赖即可:

# /// script
# dependencies = ["requests"]
# ///
import requests

print(requests.get("https://example.com").status_code)
uv run script.py

uv 会按需创建并管理隔离环境,自动安装 requests 再运行,无需手动建环境或激活;相关下载和构建数据会被缓存以加速后续运行,需要时可用 uv cache clean 清理。

写正式项目:库或应用怎么用

库项目用 --lib

个人脚本用默认(或 --no-package)布局就够;开发要发布的库,用 --lib

uv init --lib --python 3.12 my-lib

--python 3.12 会以 Python 3.12 初始化项目:设置相应的 requires-python 并生成 .python-version--lib 生成适合库的 src/ 布局,并包含 py.typed 等库模板内容。依赖照常用 uv add 添加。注意 uv python pin 3.12 只修改 .python-version,不会改动 requires-python;调整最低兼容版本时需要一并检查 pyproject.toml

可选依赖(extras)

uv add --optional web "fastapi[standard]"
uv add --optional test pytest

用户安装时可以按需选择:pip install my-lib[web]uv add my-lib[web]

构建与发布

uv build      # 在 dist/ 生成 .whl 和 .tar.gz
uv publish    # 发布到 PyPI,需先配置 token

uv publish 通过 UV_PUBLISH_TOKEN 环境变量或 --token 参数传入 PyPI Token;在 GitHub Actions、GitLab CI 等环境中也可以使用 Trusted Publishing 免 Token 发布。发布前建议先 uv build 试构建一遍。

多项目 workspace

一个仓库里放多个关联项目(比如 SDK 和它的 demo),在根 pyproject.toml 声明:

[tool.uv.workspace]
members = ["sdk", "demo"]

workspace 中的项目共享一个 uv.lock 和项目环境,uv 会统一解析各成员的依赖。成员之间需要互相引用时,在 dependencies 中声明包名,并通过 [tool.uv.sources] 将其指定为 workspace 成员(sdk = { workspace = true })。这是进阶功能,用到时再查文档即可。

部署:服务器与 Docker

服务器直接部署

git clone <仓库地址>
cd 项目目录
uv sync --locked --no-dev   # 校验 lock,并排除默认的 dev 依赖组

两个关键 flag:

  • --locked:要求 uv.lock 已存在且与项目声明一致,不一致直接报错,并禁止部署时重新解析或改写锁文件
  • --no-dev:排除默认的 dev 依赖组(--no-group dev 的别名,pytest、ruff 这类依赖都在这里)。如果项目配置了其他默认依赖组,它们仍会被安装;要排除所有默认组,用 --no-default-groups

--frozen 与之类似但更宽松:直接使用现有 lock,跳过一致性检查。它适合明确需要跳过检查的场景,比如 Docker 分层构建时只拷入了部分项目文件。

启动服务可以用 uv run,或直接指向 .venv 里的可执行文件(systemd、supervisor 等进程管理器更喜欢这种方式):

uv run --locked --no-dev gunicorn app:app
# 或
ExecStart=/srv/app/.venv/bin/gunicorn app:app

Docker 部署

以下以 FastAPI 项目为例:假设项目已经通过 uv add "fastapi[standard]" 安装依赖,并在 app/main.py 中定义了名为 app 的 ASGI 应用。

推荐的写法:从 uv 官方镜像拷二进制进容器(固定 uv 版本,与本地开发环境保持一致,避免镜像里的 uv 升级引起行为漂移;要求更高可进一步固定镜像 digest),依赖声明和源码分开 COPY 以利用层缓存:

FROM python:3.12-slim

COPY --from=ghcr.io/astral-sh/uv:0.12.1 /uv /uvx /bin/

WORKDIR /app

# 先只拷依赖声明,安装依赖(这层只有改依赖时才会重建)
COPY pyproject.toml uv.lock ./
RUN uv sync --locked --no-dev --no-install-project

# 再拷源码,安装项目本身
COPY . .
RUN uv sync --locked --no-dev

ENV PATH="/app/.venv/bin:$PATH"
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

几个要点:

  • 依赖层和源码层分开:只改代码不触发依赖层重建,构建速度快很多
  • 第一次 uv sync--no-install-project:源码还没拷进来,只装依赖
  • 两层都能用 --locked:每层都同时拷入了 pyproject.tomluv.lock,一致性检查能通过;只有 workspace 这类声明文件拷不全的场景才需要 --frozen
  • 单项目容器中,也可以把 UV_PROJECT_ENVIRONMENT 设为 /usr/local,直接装进系统 Python 前缀,PATH 都不用改。不要在多个项目共享的 Python 环境里用这种方式——uv sync 的精确同步可能移除其他项目安装的包
  • 别忘了在 .dockerignore 里排除 .venv,否则本机虚拟环境会被打进镜像

这些文件都是什么

执行 uv init,再运行一次 uv adduv syncuv run 后,一个完整的项目通常包含这些文件(.venvuv.lock 都是首次同步时才生成,uv init 本身只创建其余部分):

my-project/
├── .venv/            # 首次同步时生成的虚拟环境,不要提交
├── .gitignore        # git 忽略规则
├── .python-version   # 项目使用的 Python 版本
├── README.md         # 项目说明
├── pyproject.toml    # 项目配置与依赖声明
├── src/
│   └── my_project/   # 项目源码
└── uv.lock           # 首次锁定或同步时生成

0.12 默认模板没有根目录 main.py:命令行入口声明在 pyproject.toml[project.scripts],实现放在 src/my_project/main();旧式平铺布局的 main.py 只在 --no-package 时生成。

pyproject.toml

项目的"身份证"加"采购单":项目名、版本、Python 版本要求、依赖列表,以及可选的构建系统和工具配置(ruff、mypy 的配置也写在这里)。pyproject.toml 是现代 Python 项目的统一配置文件,其中 [project] 表遵循 PEP 621,用于声明项目名称、版本、Python 版本要求和运行依赖等元数据。它可以取代过去写在 setup.pysetup.cfg 中的大部分配置;在 uv 管理的新项目中,依赖通常也直接声明在这里,无需再手动维护 requirements.txt,但后者仍是有效的依赖格式:

[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["requests>=2.32"]

依赖一般由 uv add 帮你维护,很少需要手写。0.12 默认模板还会在 [project.scripts] 里声明 my-project = "my_project:main",这就是 uv run my-project 能直接运行的来源。

uv.lock

锁文件,记录所有依赖(包括间接依赖)的精确版本、哈希和来源。uv.lock 是跨平台锁文件,同一份文件可以同时记录不同操作系统、架构和 Python 版本对应的解析结果,使不同机器在各自平台条件下使用一致、可重复的依赖版本——"在我这能跑,到你那就报错"的解药。必须提交到 git,可以类比前端的 package-lock.json

.python-version

通常包含一行 Python 版本请求(如 3.12,表示 3.12 版本系列,不保证所有人为完全相同的补丁版本),让 uv 为项目选择同一 Python 版本系列;uv 也支持比单纯版本号更复杂的版本请求。由 uv python pin 3.12uv init --python 3.12 生成;同步时如果本机没有这个版本,uv 会自动下载。建议提交到 git,让团队成员使用同一版本系列。

.gitignore

git 的忽略清单。它不是 uv 发明的,但 uv init 会自动生成一份,包含 __pycache__/dist/.venv 等常见条目。.venv 一定不能入库——它是本机生成、动辄几百 MB 的虚拟环境,别人可以通过 uv sync 一键重建。

.venv

uv 在项目根目录创建的虚拟环境。Windows 下解释器在 .venv\Scripts\python.exe,Linux 下在 .venv/bin/python。平时不用管它,uv run 会自己找;想删就 rm -rf .venv 然后重新 uv sync

实用小技巧

uv 当 pip 用:老项目还在用 requirements.txt?uv venv 之后 uv pip install -r requirements.txt 兼容绝大多数常见 pip 工作流(但不是 pip 的完整复刻)。新项目建议直接用 uv 的项目管理,一条命令同时维护 pyproject 和 lock。

uvx 临时工具

uvx ruff check .    # 临时跑一次 ruff,不污染环境
uvx black .         # 临时运行,不全局安装

uv tool 全局工具(相当于 pipx):

uv tool install ruff
uv tool upgrade --all

国内镜像加速。PyPI 走清华源,Python 本体下载走南京大学镜像(如果安装某些较旧的 Python 版本遇到 404,可以切换到 npmmirror 的 https://registry.npmmirror.com/-/binary/python-build-standalone/ 等其他镜像,或暂时恢复官方源):

export UV_DEFAULT_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple
export UV_PYTHON_INSTALL_MIRROR=https://mirror.nju.edu.cn/github-release/astral-sh/python-build-standalone/

缓存:uv 把下载过的包缓存到本地(Linux 在 ~/.cache/uv,Windows 在 %LOCALAPPDATA%\uv\cache),删掉 .venv 或切换项目时,已有缓存通常可以复用,减少重复下载。磁盘紧张时 uv cache clean 清空。

总结

uv 把 Python 开发里最繁琐的环境与依赖管理,压缩成了几条命令。记住最小集就够了:

uv init      # 新建项目
uv add 包名   # 加依赖
uv run 命令   # 跑代码,不用激活环境
uv sync      # 别人拿到项目后一键还原

官方文档:https://docs.astral.sh/uv/


本文由 Wuqi 原创,转载请注明出处。

📖相关推荐