ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

uv 实战指南:从 pip+venv 迁移到统一 Python 工具链

2026/9/18 2:47:23 拓冰建站 浏览量
uv 实战指南:从 pip+venv 迁移到统一 Python 工具链 我前阵子帮同事配置新开发机习惯性打开终端就是一步到位先装 uv然后把项目仓库拉下来执行uv sync --frozen几秒钟之后环境就绪连虚拟环境激活那一步都省了。同事问我“你的环境到底建在哪了”我愣了一下才反应过来——我确实已经很久没有手动敲过python -m venv .venv和source .venv/bin/activate了。这篇东西就是我日常使用 uv 的记录主要覆盖安装、环境切换、Python 版本管理、国内网络下装 Python 的方式、离线电脑搭环境以及一些踩过之后才记住的坑。如果你正从 pip venv 往 uv 迁移或者需要在内网环境里复现 Python 开发环境这篇应该能省你不少事。1. 从 pip venv 迁到 uv先搞清楚它替你干了什么1.1 uv 的身份不是“又一个包管理器”说实话我最早看到 uv 的时候以为它只是 pip 的提速替代品用了两周才发现这个判断是错的。uv 是 Astral 公司用 Rust 写的 Python 工具链它把 Python 解释器管理、虚拟环境、包安装、依赖锁定、项目同步这几个步骤全串起来了。传统的工作流是到官网或者 pyenv 装一个 Python 解释器。执行python -m venv .venv创建虚拟环境。source .venv/bin/activate激活环境。pip install xxx装依赖然后靠pip freeze导 requirements.txt。换机器时读 requirements.txt重建环境。这套流程本身没问题但每一步都需要手动接管。uv 把流程压缩成uv init hello-uv # 初始化一个项目 cd hello-uv uv add requests # 加依赖自动创建 .venv、写 pyproject.toml、生成 uv.lock uv run python main.py # 直接运行不激活环境也能跑就这四行环境就绪、依赖锁定也完成了。对我这种要同时维护几个项目的人来说最大的改变不是“快”而是“每一步的状态都是可追踪的”。项目里留下pyproject.toml、uv.lock、.python-version三个文件换机器、换人、上 CI都能复现同一个环境。1.2 Windows / Linux / macOS 的安装方式uv 的安装没有太多花样官方推荐直接跑安装脚本macOS / Linuxcurl -LsSf https://astral.sh/uv/install.sh | shWindows PowerShellpowershell -ExecutionPolicy ByPass -c irm https://astral.sh/uv/install.ps1 | iexWindows 也可以直接用 wingetwinget install --idastral-sh.uv -e如果你本来就在用 pip装起来更简单pip install uv这种方式适合已经由 pip 管着全局工具链的人缺点是后续升级 uv 需要走pip install -U uv而不是 uv 自己的uv self update。如果没想好我建议还是用官方脚本让 uv 独立管理自己别和 pip 的全局环境搅在一起。几个平台的安装路径有差异后面排查 PATH 问题要依赖这个认知Linux / macOS 官方脚本默认装到~/.local/bin/uvWindows 官方脚本默认装到%USERPROFILE%\.local\bin\uv.exe通过 pip 安装则在 Python 的Scripts或bin目录里装完之后任意终端执行uv --version能看到版本号这一步就算过关了。2. 安装后最常见的一道坎uv is not on path2.1 报错的来龙去脉我见过太多人倒在第一步明明安装脚本跑完了最后一行字却说uv is not on path. Download and install uv from https://astral.sh/uv。这个提示其实很有迷惑性它暗示“安装失败”但绝大多数情况下 uv 已经装好了真正的问题是你的 shell 环境变量还没加载到它所在的目录。以官方 install.sh 为例脚本末尾会往~/.bashrc、~/.zshrc或~/.profile里追加一行export PATH$HOME/.local/bin:$PATH这行代码要等新的 shell 会话启动时才会生效当前终端窗口并不会自动刷新。所以安装完立刻敲uv大概率就是 “command not found”或者直接看到那句完整的报错。2.2 三步定位和修复如果你也碰到这个问题按下面这个顺序排查比在网上乱搜快很多。第一步先确认 uv 文件到底装到哪了。Linux / macOS 看which uvWindows 看where.exe uv如果这里能输出路径说明 uv 本体没有问题纯粹是 PATH 没包含这个目录。如果这里没有输出再检查安装脚本的UV_INSTALL_DIR有没有被改动或者是不是装到了别的用户目录下。第二步确认目标目录是否在 PATH 中。Linux / macOS 执行echo $PATHWindows PowerShell$env:Path重点看有没有~/.local/bin/%USERPROFILE%\.local\bin这一项。没有的话先临时加进去验证一下export PATH$HOME/.local/bin:$PATHWindows PowerShell$env:Path $env:USERPROFILE\.local\bin;$env:Path这时候再敲uv --version能出版本就说明方向对了。最后一步就是把 PATH 固化。Linux / macOS 重新source ~/.bashrc或者新开一个终端窗口Windows 重启终端或者去“系统属性 - 环境变量”里手动确认用户 PATH 里是否多出了.local\bin。还有一种常见情况是 CI 或自动化脚本里报错。很多脚本用的是非交互式 shell.bashrc并不会被加载这时候集中在脚本开头先export PATH$HOME/.local/bin:$PATH或者直接写~/.local/bin/uv的绝对路径即可不要在同一个脚本里依赖交互式配置。3. 初始化项目与虚拟环境切换的实操记录3.1 uv init、uv venv、uv add 三者分工刚开始切换 uv 的人最容易混的就是这三个命令我一开始也绕了一下。简单说uv init负责生成一个 Python 项目的基本骨架。uv venv只负责创建虚拟环境不关心项目元数据。uv add是“项目级”加依赖它会把包写入pyproject.toml和uv.lock并同步装进虚拟环境。执行uv init hello-uv之后你会看到下面这些文件hello-uv ├── .gitignore ├── .python-version ├── README.md ├── main.py └── pyproject.toml新版 uv 默认生成的pyproject.toml大概是[project] name hello-uv version 0.1.0 description Add your description here readme README.md requires-python 3.12 dependencies []注意里面的requires-python和.python-version都记录了 Python 版本。这意味着项目对解释器的要求是写进文件的队友克隆后不需要在 README 里专门注明“请用 Python 3.12”uv 会自己读。uv venv一般在两种场景下用一是你想单独临时建一个干净环境不需要 pyproject.toml二是你拿到一个老项目项目里还没有 uv 配置只想快速建个.venv往里塞东西。它本质上是传统python -m venv的替代品。uv add才是日常主力。例如uv add requests uv add fastapi0.110,0.112 uv add --dev pytest ruff执行后 uv 会创建虚拟环境如果还没有把包装进去然后在pyproject.toml的dependencies里记录再生成uv.lock。这里有个隐藏行为值得记住uv add永远是“项目级”的它一定写入 pyproject.toml。如果你只是临时想装个包试试不想污染项目 metadata应该用uv pip install。3.2 用 uv python 做版本管理和环境切换uv 最让我觉得顺手的功能是它连 Python 解释器也能管。以前我用 pyenv还得先装 pyenv 插件再pyenv install 3.11.9然后切版本。uv 内部直接集成了类似能力。# 列出 uv 能管理的 Python 版本 uv python list # 安装指定版本 uv python install 3.11 # 查看当前项目会使用哪个 Python uv python find # 把当前项目的 .python-version 切换为 3.11 uv python use 3.11当你在项目里执行uv python use 3.11uv 会改写.python-version文件。之后uv run python -V就固定走 3.11不会因为系统默认 Python 是 3.12 或者 3.10 而跑错。如果你已经在别的目录建好了环境想切到指定版本可以直接用uv venv --python 3.11这会创建一个使用 3.11 的.venv。如果已有旧环境通常建议先删除.venv再重建避免解释器混着用。我实测下来直接在一个已经存在的.venv上覆盖--python参数效果并不稳定还是删干净重来最省心。3.3 删除环境与清理命令uv 其实没有一个专门的“删除环境”命令虚拟环境本质就是一个目录删除它最好的方式依然是rm -rf .venvWindows 上就是删掉对应的.venv文件夹或者用Remove-Item -Recurse -Force .venv。我更想提醒的是另外两个容易忽略的清理场景删除 uv 管理的 Pythonuv python uninstall 3.11它会清理 uv 专门下载的 Python 解释器但不会动系统自带的 Python。这个命令容易让人误判我之前一度以为它会把项目环境也删掉实际上环境还在只是解释器缓存被清了。清理安装包缓存uv cache clean会清空整个全局缓存下次uv sync时所有包都要重新下载慎用。日常更推荐uv cache prune它只清理没有被引用的缓存条目。4. 国内镜像让 uv python install 3.11 不再卡死4.1 uv 下载 Python 的方式和痛点搜索“uv python install 3.11 国内镜像”的人十有八九是卡在下载那一步。uv 安装 Python 时默认从 GitHub 上的python-build-standalone项目下载预编译解释器文件托管在 GitHub Releases 上。国内网络访问这个地址经常超时尤其在公司网络里动辄百八十 MB 的解释器压缩包下载一半断掉是常有的事。这本身不是 uv 的 bug而是网络链路问题。只要理解了“uv 就是从某个 URL 前缀下载文件”这个原理解决办法就很清晰。4.2 UV_PYTHON_INSTALL_MIRROR 怎么配uv 提供了一个环境变量UV_PYTHON_INSTALL_MIRROR用来替换默认的下载地址前缀。设置方式export UV_PYTHON_INSTALL_MIRRORhttps://你的镜像地址如果你能访问 GitHub 但速度不稳定可以用常见的加速前缀例如把https://github.com/astral-sh/python-build-standalone/releases/download映射到代理地址。具体加速域名时效性很强我不在这里贴固定的指路链接但思路是镜像地址要补齐到releases/download这一层因为 uv 在后面会自动拼接/tag/文件名。更稳定、更可控的方案是自建本地镜像在有网的机器上手动下载好python-build-standalone对应的 release 文件放到内网静态文件服务里然后把UV_PYTHON_INSTALL_MIRROR指过去。这样既不依赖第三方可用性也解决了内网机器的下载问题。4.3 兜底方案让 uv 直接用系统 Python如果你眼下只是想赶紧把项目跑起来不一定要让 uv 自己下载 Python。uv 很聪明的一点是它不排斥外部解释器你完全可以让它使用系统已经装好的 Python。uv venv --python /usr/bin/python3.11或者uv venv --python python3.11只要这个命令能被系统找到uv 就会直接基于它创建虚拟环境。这样你就绕开了 Python 下载环节。代价是 Python 解释器版本由系统决定你在uv python list里看不到被 uv 管理的版本但对大多数业务开发完全够用。另外还有个实用技巧如果你只是想快速安装 uv 本体且豆渣项目里已经有 Python 环境可以通过 pip 从国内 PyPI 镜像安装 uv例如pip install uv -i https://pypi.tuna.tsinghua.edu.cn/simple这样至少 uv 本体可以顺利落地之后再考虑 Python 解释器的获取渠道。5. 无网络电脑搭建 Python 虚拟环境的离线方案5.1 先弄懂 uv 的缓存机制无网络电脑最麻烦的不是项目代码而是依赖包和 Python 解释器。uv 在安装一个包时不会直接把下载的 wheel 用完就扔而是会存到本地缓存目录里。默认位置Linux / macOS~/.cache/uvWindows%LOCALAPPDATA%\uv\cache同时uv 自己下载的 Python 解释器也会单独存在一块数据目录通常是Linux / macOS~/.local/share/uv/pythonWindows%LOCALAPPDATA%\uv\python理解了这个结构离线方案就顺理成章在一台有网的、和目标机器同系统同架构的机器上先把依赖和解释器都准备好然后整个搬到离线机器上。5.2 在联网机器上准备“离线部署包”假设你手上的项目已经有pyproject.toml和uv.lock。在一台联网 Linux 机器上执行uv sync这条命令会把项目所有依赖下载到缓存同时创建好.venv。此时项目目录结构大概是这样myapp ├── .venv ├── .python-version ├── .gitignore ├── pyproject.toml └── uv.lock然后把三样东西打包tar -czf uv-offline-bundle.tar.gz \ myapp \ ~/.cache/uv \ ~/.local/share/uv/python注意打包的是整个项目目录和 uv 的全局数据目录不是只打包.venv。这是很多教程没讲透的地方单独拷贝.venv在换机器时大概率挂掉因为虚拟环境里的pyvenv.cfg记录了解释器的绝对路径换机器后这些路径对不上。把 uv 的 Python 数据目录一起带过去uv 才能重新识别解释器并基于它重建环境。5.3 离线机器上的恢复操作在离线机器上先放好 uv 本体。如果机器上没有 uv直接把有网机器上的uv二进制文件在~/.local/bin/uv连同上一步的 tar 包一起拷过去放在~/.local/bin/下授予执行权限即可。然后把压缩包解压到对应位置。如果缓存目录不是默认路径可以设置export UV_CACHE_DIR$HOME/.cache/uv最后在项目目录里执行uv sync --offline--offline表示 uv 不会发起任何网络请求只读缓存和 lock 文件。如果一切顺利它会在几秒钟内重建.venv依赖齐全直接就能跑。这套方案的三大要点我划一下重点系统架构必须一致。Linux x86_64 打包的缓存不要拿去 Windows 或 ARM 机器上指望能用。tar 包里的.venv目录其实可以删掉只要缓存和 Python 数据目录在uv sync --offline会根据uv.lock重新生成。保留.venv只是加载少等一会儿并不是必要条件。公司内网机器如果还有部分网络可用也可以不一口吃成完全离线先设置好代理再uv sync然后断网重试--offline这样更保险。6. 用 uv 管项目依赖半年后我留下的几条使用经验6.1 uv add 和 uv pip install 怎么选我见过不少人装依赖一律uv pip install然后发现 pyproject.toml 里什么都没记录又回来问“怎么依赖丢了”。这里区分很简单需要长期留在项目里的依赖用uv add。只是临时验证一下、不打算写进项目文件的用uv pip install。uv pip install更像是 pip 的替代品它不会记录到项目元数据适合快速验证某个库是否存在兼容问题。如果你需要一个真正的项目环境老老实实走uv adduv sync让uv.lock帮你锁定全部传递依赖。6.2 uv.lock 和 .python-version 要不要进版本库一定要提交而且没有例外。uv.lock是把整个依赖树精确到版本的文件它保证团队每个人装到的依赖完全一致。.python-version则锁定了解释器版本避免“我本地 3.11 能跑你 3.12 挂了”的经典纠纷。拿到一个陌生项目时我通常这样快速进入状态cd repo-name uv sync --frozen uv run python main.py--frozen是告诉 uv完全按uv.lock来不要尝试更新任何依赖。这个方法在 CI 里也适用比传统的pip install -r requirements.txt快得多。6.3 高频命令速查表为了方便查看我把从传统工作流到 uv 的对应关系整理成一张表目标传统方式uv 方式创建虚拟环境python -m venv .venvuv venv激活虚拟环境source .venv/bin/activatesource .venv/bin/activate 或 uv run安装依赖pip install requestsuv add requests临时安装依赖pip install requestsuv pip install requests导出依赖清单pip freeze requirements.txtuv export --frozen requirements.txt按清单恢复依赖pip install -r requirements.txtuv sync / uv sync --frozen安装 Python 版本pyenv install 3.11uv python install 3.11切换 Python 版本pyenv local 3.11uv python use 3.11清理缓存手动删轮子 / 清理 virtualenvuv cache clean / uv cache prune临时运行命令行工具npx 的 Python 版本uvx ruff check .6.4 三个容易犯迷糊的地方第一个是uv run与source .venv/bin/activate的选择。日常开发我倾向于不激活环境所有命令都通过uv run前缀执行这样不会因为切换目录搞混环境。但如果你开着 IDE 或者需要调试器激活环境更方便看编辑器右下角解释器版本也更直观。两种方式各有场景不是非此即彼。第二个是 uv 版本迭代很快不同版本间命令行行为可能有差异。比如uv python uninstall是后来才支持的早期只能用uv python install加rm -rf手动处理。遇到命令不存在不一定是你操作错了先看看uv --version再对照官方文档比较稳妥。第三个是 Windows 上的中文路径问题。如果项目路径中带非 ASCII 字符某些轮子安装时可能报编码错误这不是 uv 的锅但会让不少人误以为是环境坏了。解决办法很简单项目目录不要放在带中文的路径下用纯英文目录最省心。最后分享一个小习惯我每个项目里都会放一个scripts/bootstrap.sh内容就两行——一行安装 uv一行uv sync --frozen。不管是新同事入职还是 CI 跑测试又或者是临时拉取线上分支排查问题全部走同一个初始化逻辑。稳定可复现还不用反复解释环境怎么配。这个习惯让我几乎告别了“环境问题排查大会”也是我这段时间用 uv 最大的收获。