十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

uv入门实战:从安装到踩坑,Python包管理器的极速体验

uv入门实战:从安装到踩坑,Python包管理器的极速体验 你可能已经在技术社区里刷到过uv这个词了——它号称是Python包管理器的终极答案。一开始我不信毕竟Rust写的东西这几年见得太多了动不动就性能提升10倍结果自己一跑确实快但离惊艳还差口气。直到我把一个用pip管理了半年的FastAPI项目切到uv上创建虚拟环境从原来的3秒缩到了0.1秒安装几十个依赖几乎是一瞬间完成才真正意识到这不是营销文案。这篇文章就是我基于实际使用整理的uv学习笔记。覆盖从安装、创建虚拟环境、管理Python多版本、切换环境、配置镜像、装PyTorch GPU版到踩坑记录的全过程适合刚开始接触uv的人也适合正在纠结要不要从pip/conda/poetry迁移过来的朋友。我会尽量把每一步的为什么这样做讲清楚而不是甩一堆命令让你硬抄。顺便说一句uv坐标那个词条确实存在但那是3D图形学里的UV贴图坐标系跟咱们今天说的Python工具完全是两码事。我在第一次搜索的时候也被清一色的图形学文章整懵过所以看到这个热词必须出来澄清一下。1. 为什么我决定把pip换成uv在聊uv的安装和使用之前先花点篇幅讲讲它到底解决了什么痛点。如果你只用pip requirements.txt做过小项目可能觉得GitHub上那些吹uv的博主都在小题大做。但当你维护一个依赖几十个包、还牵扯到CUDA版本、Python多版本协作的项目时pip的脆弱性会被放大到让你抓狂。我用pip最痛苦的两件事第一每次创建一个新项目都要等好几秒python -m venv .venv之后再source .venv/bin/activate然后才开始慢慢爬依赖碰到某个包要求编译当场心态爆炸第二pip的依赖解析在遇到复杂的版本约束时会咔咔给你装一个并不满足约束的组合然后运行时报ModuleNotFoundError你一脸懵逼。后来我短暂用过poetry它把依赖锁定和发布管理做得很好但缺点是慢而且跟一些老项目的setup.py兼容性不佳。Conda则是被Anaconda默认仓库的下载速度劝退了绕镜像源绕得心累。uv的出现等于把我记忆里这些解决问题的方案又重新做了一遍。它是Astral公司就是做ruff那个团队用Rust写的高性能Python包管理器核心卖点就三个极快的依赖解析、极快的二进制安装缓存、内置Python版本管理。不是通过某一种加速技巧而是从头设计上就跟pip走了完全不同的路线比如用并行下载、全局缓存、符号链接复用已缓存的wheel所以在大多数场景下都能把安装时间缩短一个数量级。从命令行设计来看uv几乎兼容了pip的所有常用命令参数这意味着你不需要重学一套心智模型之前怎么用pip现在就怎么用uv pip同时它又增加了uv add、uv run、uv python install这类面向项目管理的高级命令。我在实际用了三四天之后就果断把所有新项目的默认工具改成了uv。2. uv安装全路线从一键脚本到离线安装2.1 官方推荐的安装方式安装uv不像安装Anaconda那样需要下载几百MB的安装包也不像传统pip工具那样要先有个能用的Python环境。它本质上是一个独立的二进制文件安装就是把这个二进制放到PATH目录里。macOS和Linux用户直接跑官方一行命令curl -LsSf https://astral.sh/uv/install.sh | shWindows用户用PowerShellpowershell -c irm https://astral.sh/uv/install.sh | iex如果你在Windows上更喜欢用包管理器也可以winget install --id astral-sh.uv安装完成之后建议先把当前终端关掉重新打开让PATH刷新。然后验证uv --version我第一次跑的时候没刷新终端直接提示找不到命令当时还以为脚本没装上。后来发现是PATH没生效这种事往往浪费时间提醒新同学注意。2.2 用pip安装适合不想用curl的场景有些内网机器或者公司电脑出于安全策略不允许执行curl管道安装脚本但恰好已经有一个可用的Python环境这时候用pip安装是最省事的pip install uv这条命令会把uv以Python包的形式装进去实际可执行文件位于pip的Scripts目录下效果跟官方二进制差不多。它的好处是跟你的Python环境绑定升级时直接pip install -U uv坏处是如果你换了一个conda环境原环境的uv就找不到了。所以如果是个人开发机我还是推荐直接用官方脚本全局只有一个uv二进制不依赖任何Python环境这样后面用uv venv创建任何Python版本的虚拟环境时才不受绑定的Python限制。2.3 手动安装离线环境的标准动作海外服务器、内网环境、或者Docker镜像构建时网上直接拉脚本经常超时这时候需要提前把uv的二进制包下好拷进去手动放行。在GitHub releases页面找到对应平台的release包例如Linux x86_64平台是uv-x86_64-unknown-linux-gnu.tar.gz下载并解压mkdir -p ~/.local/bin tar -xzf uv-x86_64-unknown-linux-gnu.tar.gz -C ~/.local/bin解压之后~/.local/bin下会出现uv这个可执行文件确认一下有执行权限chmod x ~/.local/bin/uv然后把路径加进shell配置文件里比如在~/.bashrc或~/.zshrc中追加export PATH$HOME/.local/bin:$PATH再执行source ~/.bashrc刷新。整个过程中我没有改动默认系统的Python环境uv自己作为一个静态编译的Rust程序对这个世界的依赖只有一个可执行文件清爽得很。2.4 升级与卸载uv自带了self update命令用来升级到最新版本uv self update它会自动检测最新release并替换二进制文件我们不需要重新安装一遍。如果是从pip装的就用pip各自管理。卸载方面官方脚本安装的uv直接删除~/.local/bin/uv和~/.cache/uv目录即可几乎不留任何系统垃圾。uv的设计哲学就是二进制文件做完所有事这一点在使用体验里体现得非常彻底。3. uv虚拟环境与Python版本管理的核心操作3.1 uv venv旧时代创建环境的终结者使用pip的时候创建一个虚拟环境的标准命令是python -m venv .venvuv对应的是uv venv默认在当前目录下创建.venv文件夹。官方这样设计是为了跟.gitignore里的.venv/规则无缝衔接实际使用中你会感觉整个工作流像原生支持所有Python项目一样。更重要的一点是速度。用系统Python创建虚拟环境需要先加载解释器再复制标准库冷启动没有一秒也有两秒。uv创建虚拟环境本质上是创建一个目录结构然后把已有解释器通过链接方式关联过去所以实测基本在100毫秒到200毫秒之间。这种速度上的差异平时单次操作感知不强烈但当你写脚本循环创建多个环境做测试的时候差距就非常恐怖了。如果想把虚拟环境创建到一个指定位置或者指定解释器可以这样uv venv --path /tmp/custom-venv --python 3.12--python参数可以接受一个版本号。3.2 用uv install管理Python解释器在旧时代如果系统里没有Python 3.12你得去官网下载安装包或者用conda建一个环境还得操心路径配置。uv把这个事情也接管了。你只要写下uv python install 3.12它就会下载一个官方Python 3.12解释器放到~/.local/share/uv/python下然后uv venv --python 3.12时可以直接使用。如果觉得某个版本不再需要可以uv python uninstall 3.12查看当前所有可用版本uv python list这个内置Python管理器的方便之处在于整个团队可以共用同一个项目配置.python-version文件里面记录了项目的目标Python版本然后无论新老成员只要装了uv一条uv sync就能把正确的Python解释器拉下来并创建虚拟环境完全绕开我系统Python版本不对这类千古难题。3.3 切换Python版本与虚拟环境网上热词里有一句uv 切换环境实际要区分两个概念切换当前shell的Python版本还是切换当前项目的解释器版本。切换全局默认的Python版本用uv python pin 3.12它会写一个.python-version文件告诉uv这个项目默认使用Python 3.12。以后执行uv run python或者uv venv时都会优先读取这个文件。切换虚拟环境本身跟传统方式一样source .venv/bin/activate不过uv有更现代的做法直接用uv run来包一层例如uv run python myscript.pyuv run会自动检查.venv是否存在若不存在就根据.python-version创建然后安装锁定的依赖再运行命令。整个过程可以把激活环境这个步骤从日常开发中彻底删掉。我第一次体验到这个流程时震惊程度不亚于第一次用docker容器跑业务所有环境信息都固化在项目文件里换台电脑clone下来就能跑。3.4 结合FastAPI项目跑通真实开发流空谈命令没有感觉用一个实际的FastAPI项目演示一下从零到跑起来的完整流。mkdir my-fastapi-app cd my-fastapi-app uv inituv init会帮你生成一个最小的pyproject.toml、main.py、.gitignore等文件。接着添加依赖uv add fastapi uvicorn[standard]这条命令会分析并锁定FastAPI及其所有依赖的兼容版本在项目下创建.venv虚拟环境把所有依赖安装进这个环境并生成uv.lock文件。写一个最简单的应用from fastapi import FastAPI app FastAPI() app.get(/) def read_root(): return {hello: uv}然后直接用uv拉起服务uv run uvicorn main:app --reload我没有手动source .venv/bin/activateuv run替你把这个事情做掉了。uv.lock文件承担了类似Cargo.lock的角色记录每个依赖精确的版本和哈希保证团队所有人拿到的是完全一致的环境。这就是uv项目管理流和uv pip流之间最大的区别前者以项目为单位环境、依赖、版本全部收拢在pyproject.toml uv.lock里后者则是pip的机械化替换适合在已有的复杂工程里逐步过渡。提示对老项目你完全可以先只用uv pip install -r requirements.txt把速度提升上来以后再逐步迁移到uv add的模式。不必一次推翻重来。4. uv安装速度为什么这么快缓存机制与镜像配置4.1 一个看似离谱但真实的下载速度对比我在一个新环境里测过同一个项目一个包含Django、DRF、Pillow、Celery、Redis、psycopg2等二十多个包的项目。pip装完耗时1分40秒左右uv装完耗时6秒左右。差距接近17倍。原因首先是Rust写解析器带来的性能优势uv把依赖解析从下载式变成并发解析利用全局缓存避免重复下载。重点说下缓存。uv有一个全局缓存目录默认在~/.cache/uv它会把下载过的wheel解压后以不可变快照的方式存起来后续在任意项目中用到同一个wheel时直接在缓存里做硬链接或复制而不是重新下载。也就是说你的机器上只要曾经装过某个版本的numpy不管是在哪个项目里下次再装同一个版本时几乎是瞬间完成。这跟pip的本地缓存不太一样pip也会做http缓存放wheel但解析依赖时还是要重复扫描metadata、计算版本约束这些都需要时间和CPU。uv直接跳过这些流程因为它在往缓存里写入的时候就已经做完了解析并用锁文件记录了最终结果。4.2 配置PyPI镜像源国内网络环境下直接从官方PyPI下载经常超时。你可以在命令行里传index地址uv pip install fastapi --index-url https://pypi.tuna.tsinghua.edu.cn/simple每次传嫌麻烦就用环境变量统一指定export UV_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple写到~/.bashrc或~/.zshrc里就能永久生效。Windows用户用系统环境变量或PowerShell设置都可。如果你希望pip和uv共用一套镜像配置其实pip也读PIP_INDEX_URL但uv官方推荐的是UV_INDEX_URL和UV_EXTRA_INDEX_URL两个变量分别对应主源和追加源。例如你主源用清华镜像装普通包追加源用官方PyPI装一些镜像源里没有的特殊包export UV_INDEX_URLhttps://pypi.tuna.tsinghua.edu.cn/simple export UV_EXTRA_INDEX_URLhttps://pypi.org/simple还有更灵活的方式是在pyproject.toml里配置索引源这样同一团队不用每个人手动配环境变量[[tool.uv.index]] url https://pypi.tuna.tsinghua.edu.cn/simple default true对于企业内部私有源也可以把它声明为默认源或额外源。这样uv sync时自动走内网下载速度快且安全。4.3 安装PyTorch CUDA版本的正确姿势热词里专门有一条uv 安装 pytorch cuda版本这确实是很多人搜uv的直接原因。PyTorch的官方CUDA轮子不是放在PyPI上的而是从download.pytorch.org的whl/simple仓库提供。用uv安装时跟pip的思路一致只是命令前缀换成uv pip install或用uv add配extra index。用uv pip install先创建虚拟环境再安装的方式uv venv .venv --python 3.11 source .venv/bin/activate uv pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121如果刚才已经用官方脚配置过清华镜像可以用--extra-index-url把PyTorch仓库追加进来这样普通依赖走清华镜像torch相关走PyTorch仓库uv pip install torch torchvision torchaudio \ --extra-index-url https://download.pytorch.org/whl/cu121这里需要注意--index-url和--extra-index-url的区别前者是完全替换默认索引后者是把新索引追加为备选。用了--index-url之后如果想要也获得PyPI上的普通包必须在同一命令里把PyPI或国内镜像加回去。在实际项目中这很容易踩坑我建议直接用--extra-index-url更稳妥。对于使用pyproject.toml管理的新项目则把PyTorch的仓库配置成额外索引因为主索引仍然是PyPI/清华镜像[[tool.uv.index]] name pytorch-cu121 url https://download.pytorch.org/whl/cu121 explicit true然后在依赖声明里加上--index标记例如在[tool.uv.sources]中指定。这样uv add torch --index pytorch-cu121时就会精确从PyTorch仓库拿包同时主索引继续为普通包服务。4.4 清理缓存与限制缓存大小uv缓存无限增长之后会占用几个GB的磁盘空间这是很多人吐槽的点。可以这样清理uv cache clean想看当前缓存占用uv cache dir还可以通过环境变量控制缓存位置export UV_CACHE_DIR/path/to/your/uv-cache个人建议是不要频繁clean缓存因为缓存是提速的核心资产只有当磁盘告急时才清理。还可以用系统的定时任务定期清理超过一定大小的老缓存但uv本身没有提供按时间清理的选项我用的是Linux的cron每周跑一次uv cache prune可以识别那些不再被引用的孤儿缓存并清除比全量clean更温和。5. uv踩坑记录那些我不希望你再踩一遍的坑5.1 pyqt5的 registryhttps://pypi.tuna.ts...报错热词里出现了一条典型报错信息distribution pyqt5-qt55.15.19 registryhttps://pypi.tuna.ts...我第一次在uv里装pyqt5时也碰到过类似的东西错误里带有一段类似URL的registry前缀标识。这个问题的根源是新版PyQt5通过依赖PyQt5-Qt5和PyQt5-sip两个辅助包来拆分Qt库和绑定层而PyQt5-Qt5本身在PyPI上有多个构建来源pip/uv在解析时经常因为metadata里的direct_url.json或href来源协议产生歧义。更典型的场景是你之前在项目里已经装过pyqt5uv从某个镜像源缓存了PyQt5-Qt5的地址信息之后再次安装时就拿这个缓存地址去反查结果发现镜像源上对应的包路径变了于是产生registryhttps://...这种奇怪的URL解析错误。遇到这个问题我的处理顺序是先把安装命令换成逐个安装避免tzdata、sip等子依赖互相干扰uv pip install pyqt5-sip uv pip install pyqt5-qt5 uv pip install pyqt5如果上面失败就指定版本安装uv pip install pyqt55.15.10 --index-url https://pypi.org/simple这里故意回到官方源排除镜像源metadata不同的干扰因素。还不行就直接用--no-binary PyQt5-Qt5强制走源码编译安装虽然比较耗时但能彻底绕开wheel metadata来源问题uv pip install --no-binary PyQt5-Qt5 pyqt5这个坑的教训是pyqt5的构建链路本身就不是干净的两个包而是有多个内部跳转镜像源如果只同步了部分文件很容易触发URL异常。所以看到registryhttps://报错优先怀疑源和metadata而不是怀疑uv。5.2 sglang安装需要--prereleaseallow热词里的uv pip install --prereleaseallow sglang是一条正确的命令。sglang是一个大模型推理加速框架它的依赖里经常含有一些尚未正式发布的子依赖版本比如某些最新的triton或者torch版本。按照uv默认策略安装时不允许预发布版本必须显式放行。正常情况下如果你想装某个库的预发布版本可以用uv pip install --prereleaseallow sglang命令里也可以配合--index-url或--extra-index-url使用。需要注意的是--prereleaseallow是一个全局开关会允许所有依赖的预发布版本参与解析。如果担心某些包被意外升级到预发布版导致不兼容可以只针对单独包做预发布控制uv pip install sglang sglang-kernel0.1.0rc1 --prereleaseallow但实际操作中sglang这类框架对版本组合要求很严你不一定能精确预知哪些包需要预发布。我的建议是先用全局--prereleaseallow装好一遍如果后续要固定生产版本再逐个锁定版本号写入pyproject.toml或requirements.txt。5.3 uv与conda环境混用时要注意什么我在实际中遇到不少用户是在conda环境里用uv。这种情况下建议conda activate base之后再用uv创建虚拟环境然后通过uv python install指定要用的解释器版本让uv自行管理Python解释器而不是去用conda的python。因为uv使用的是自己的Python存储路径如果你把uv的Python指到conda的某个解释器上可能引发库搜索路径冲突尤其是当两个环境都安装了numpy、torch这类有原生库的包时运行时会出现sgemm之类底层函数找不到符号的报错。更安全的替代方案是既然你已经用上了uv就不要再依赖conda来管理Python版本了直接让uv全权负责。日常只有一个基础python和uv二进制就够了。conda只用来提供一些必须的系统级库或者mkl这类Operate库但这属于少数特殊情况绝大多数Python项目用uv来管理更轻快。5.4 uv.lock导致平台相关问题uv.lock里记录的依赖版本是跨平台的但它也会记录sys_platform、platform_machine这类环境标记。也就是说在macOS上生成锁文件后Linux上执行uv sync时会根据标记自动选择对应的wheel不会因为平台不同导致冲突。这一点比pip的requirements.txt要严谨得多。不过有一个坑老版本uv生成的lock文件里可能包含一些pre-release的标记新版本uv解析时如果默认不允许pre-release会提示需要--prereleaseallow才能继续。很多人被这个报错弄懵。我的处理方式是先跑一下uv lock --upgrade让它按当前的uv版本重新解析并升级锁文件再尝试uv sync。5.5 离线安装时的哈希校验失败在隔离内网环境里离线安装包时如果源里metadata的sha256跟lock文件或requirements中的不匹配uv会直接中止安装。它不像pip那样可能只是警告一下。这个严格模式安全但也导致很多人第一次用uv内网源时直接失败。解决办法重新生成requirements或lock文件确保哈希一致。例如uv pip compile requirements.in -o requirements.txtuv pip compile会生成带精确哈希的锁定文件然后离线安装时用uv pip install -r requirements.txt离线环境建议预先在能上网的机器上用uv pip download把wheel打包好再拷到内网然后配合--find-links安装。6. 从命令行到项目级工具uv的进阶武器6.1 uv toolpipx的完美替代uv内置了uv tool install命令用来安装一些命令行工具比如ruff、black、cookiecutter、pre-commit等。它做的事情是自动创建一个隔离的虚拟环境来安装工具然后把可执行文件软链到PATH可以找到的目录从而使每个命令行工具都拥有独立的依赖环境避免互相污染。这个功能本质上是pipx的替代品但速度和资源占用要好得多。用法示例uv tool install ruff安装之后直接在任意目录执行ruff check即可不需要激活任何环境。查看已安装的工具uv tool list卸载时自动清理整个虚拟环境uv tool uninstall ruff6.2 uv run环境即运行前面FastAPI实战中提到过uv run再补充一个应用场景当项目里没有.venv也没有pyproject.toml时uv run会临时创建一个带依赖的环境来执行命令适合快速试验某一个包而不想污染全局环境。例如uv run --with flask python app.py这个命令会临时装一个flask然后运行app.py运行完环境就丢弃下一次仍然重新创建。这等于把Python脚本的便携运行提升到了NPM npx的水平很多时候我的临时小脚本都这样跑。6.3 uv sync一条命令拉齐所有开发环境对于协作项目只要有pyproject.toml和uv.lock团队成员只需要uv sync就可以完成创建虚拟环境、安装所有依赖、安装项目本身的editable包、复制.env.example等全部工作。在CI/CD流水线里同样只需要一行命令。跟传统pip install -r requirements.txt相比它多了一个精确到哈希的锁文件这使得经过一段时间后CI上构建复现生产的概率大大提高。6.4 项目内迁移旧pip项目的小技巧如果你有一个旧的pip管理项目不想手工把requirements.txt改写成pyproject.toml依赖列表可以先用uv pip compile requirements.in -o requirements.txt得到带哈希的锁定文件如果想直接生成pyproject.toml风格的依赖声明也可以使用uv add -r requirements.txt注意这个命令会把requirements.txt里的每个包都作为依赖写入pyproject.toml包括那些间接依赖所以生成之后还需要人工清理一遍把明显的过渡依赖删掉。这个方法能大大加快迁移速度不过我建议新项目从一开始就用uv add避免后面重复劳动。写在最后从第一次运行uv --version算起到现在已经大半年。中间踩过一些坑也对比过不少替代方案。如果让我用一句话总结uv对我来说不是一个又一个包管理器而是一个把Python环境编排从手工时代带到了自动时代的转折点。最后分享一个小技巧把uv sync和uv run当作默认入口后我在IDE里也完全不需要手动切换解释器了——直接在项目根目录跑uv run,然后让IDE使用.venv下的解释器路径即可。换笔记本、重装系统、新人入职所有环境配置时间全部被压缩到一条命令以内。这种体验一旦习惯真的很难再回到pipvirtualenv的手工作坊模式了。
返回列表