uv:Python项目管理的终极利器


如果条件允许,一定要先试试uv。如果不行,再考虑其他方法。

这是一个帕累托最优的解决方案,因为它比纠结于该做什么更容易,而且你很少会后悔。实际上,使用它的成本很低,但它带来的价值却相当高。

帕累托(Pareto)是一个经济学概念,源自意大利经济学家维尔弗雷多·帕累托(Vilfredo Pareto)的研究。他观察到,在大多数情况下,80%的结果往往来自于20%的原因,这就是著名的“帕累托法则”或“80/20法则”。

Python社区非常庞大且多样化。有学生、数据科学家、AI开发者、Web开发者、系统管理员、生物学家、地理学家、插件作者……他们可能在大学、政府部门、初创公司、军队、实验室或大公司工作。
他们的操作技能、经验、环境和限制各不相同,工具越通用,我就越推荐它。

这与PHP、JS、Java或Ruby的情况完全不同。

因为我是一名自由职业开发者,同时也是一名培训师,所以我能够涉足这些领域,并且我见过所有其他工具都失败了。比如pyenv、poetry、pipenv、pdm、pyflow、pipx、anaconda……

事实上,这个博客之所以开始流行,是因为一篇文章:为什么不告诉人们“简单地”使用pyenv、poetry、pipx或anaconda。

所以我不想给人们虚假的希望,也不想向他们推销那些只在我的幻想中有效的东西,不幸的是,大多数极客都是这样做的。
现在我已经了解了uv的使用方法和它失败的原因,我不仅可以告诉你应该使用它,还可以告诉你为什么。

uv试图解决什么问题
我再强调一次,Python中启动问题是万恶之源。引导问题指的是配置Python本身,并配置新项目,以便你以后可以安装依赖项或构建包。你以后遇到的大多数问题(比如打包问题)实际上都源于此。

这是因为:

  1. 安装Python的方法有很多种,每种方法都有不同的默认设置和问题。而且这些也因操作系统而异。
  2. 在安装Python之前需要了解很多信息,而Python是一种特别适合初学者的语言,从定义上来说,初学者不需要了解这些。
  3. Python的使用环境如此之多,以至于很难创建一个“适用于所有环境的教程”。在封闭的公司Windows笔记本电脑上提供的Python体验与Debian爱好者笔记本电脑上的体验完全不同。
  4. 很少有人能就此事给出好的建议,但每个人和他们的猫都用权威的语气谈论这件事。网上有太多关于这件事的废话。
  5. 有许多工具试图解决这一问题,因此我们现在面临选择悖论。
  6. PATH、PYTHONPATH、糟糕的命名约定、在同一台机器上有多个Python版本、Linux上的可选包以及Python作为系统依赖项,这些都会让你有千万种方法可以自掘坟墓。
  7. -m和py未能完成任务。大多数人甚至不知道它们的存在。
  8. 编译扩展的流行为混合增添了很多乐趣。

人们会遇到与所有这些直接相关的问题,但根本不知道情况是如何的,只会说“Python打包很糟糕”之类的话,因为他们会责怪他们试图使用的东西,而不是他们不知道的根本原因。

因此,一个优秀的Python项目管理工具应该具备以下特质:

  1. 独立于Python引导程序,因此不存在先有鸡还是先有蛋的问题,也可以解决PATH和PYTHONPATH问题。
  2. 能够在所有情况和平台上以统一一致的方式安装和运行Python。
  3. 在基本工具(pip和venv)与其自身之间提供桥梁。
  4. 具有非常强大的依赖解析器。
  5. 使简单的事情变得简单(安装东西),使复杂的事情变得可能(在不同于开发的操作系统上安装锁定的依赖项)。
  6. 所有这些都易于安装和使用,当然,非常可靠,你可以充分信任它,这是你的堆栈的最重要方面之一。
这有什么大不了的?

正确完成启动
uv的愿景非常出色。

这并不是偶然,而是由Astral非常有才华和勤奋的团队精心策划的。
首先,他们让它完全独立于Python本身。无论你安装和更新uv还是Python,都不会相互影响。不存在任何可能以任何方式影响PATH或导入问题的Python引导问题。

因此,在安装时,你无需了解太多有关Python生态系统的知识。无需对安装位置(在系统中?在venv中?)或新关键字或弃用将如何影响它感到困惑。

然后,他们开始提供pip和venv界面,以便你可以使用现有的项目、工具和范例。这是uv被低估的好处。它不仅使采用变得更容易、更不可怕,而且它还可以:

  1. 表明Astral尊重现有社区。
  2. 承认世界各地已存在的大量遗留代码的重要性。
  3. 表明他们愿意承担多年开发和维护这段相当肮脏的历史的成本。
对我来说,这表明“我们了解我们的部落,并且我们对此很认真”。

这也意味着你可以像以前一样使用pip和venv(甚至是pip-tools),但永远不需要再学习任何东西。你不必了解uv run、uv add或uvx。你在基本任务中获得的可靠性和速度足以证明迁移的合理性,因为它本质上不需要花费任何成本,因为它是相同的工作流程,只是速度更快,错误更少。

所以,即使他们就此止步,uv仍然会带来净收益。
但当然,他们没有这么做。

他们添加了一种安装Python的方法:

  1. 以统一的方式跨所有操作系统。
  2. 无需管理员权限。
  3. 独立于系统。
  4. 安装多个版本不会发生冲突。
  5. 全部使用相同的stdlib(是的,到处都是tkinter!)。
  6. 包括Pypy和No-GIL版本(!)。
  7. 无需垫片、无需编译,仅需合理的默认值。

在撰写本文的这一部分时,我用uv花了几秒钟安装了“pypy3.8”。我甚至不记得该怎么做,但API和帮助消息非常清晰,我很快就搞明白了,然后我的机器上就出现了一个新的Python。

❯ uv python list
cpython-3.14.0a4+freethreaded-linux-x86_64-gnu    <download available>
cpython-3.14.0a4-linux-x86_64-gnu                 <download available>
cpython-3.13.1+freethreaded-linux-x86_64-gnu      <download available>
cpython-3.13.1-linux-x86_64-gnu                   /usr/bin/python3.13
cpython-3.13.1-linux-x86_64-gnu                   /bin/python3.13
...
cpython-3.8.20-linux-x86_64-gnu                   <download available>
cpython-3.7.9-linux-x86_64-gnu                    /home/user/.local/share/uv/python/cpython-3.7.9-linux-x86_64-gnu/bin/python3.7 -> python3.7m
pypy-3.10.14-linux-x86_64-gnu                     <download available>
pypy-3.9.19-linux-x86_64-gnu                      <download available>
pypy-3.8.16-linux-x86_64-gnu                      /home/user/.local/share/uv/python/pypy-3.8.16-linux-x86_64-gnu/bin/pypy3.8 -> pypy3
pypy-3.7.13-linux-x86_64-gnu                      /home/user/.local/share/uv/python/pypy-3.7.13-linux-x86_64-gnu/bin/pypy3.7 -> pypy3

❯ uv python install pypy3.8
Installed Python 3.8.16 in 2.71s
 + pypy-3.8.16-linux-x86_64-gnu

❯ uvx -p pypy3.8 python
Python 3.8.16 (a9dbdca6fc3286b0addd2240f11d97d8e8de187a, Dec 29 2022, 11:45:13)
[PyPy 7.3.11 with GCC 10.2.1 20210130 (Red Hat 10.2.1-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>> import tkinter
>>>> import zipfile
>>>> import ssl
>>>>

它显示“在 2.71 秒内安装了 Python 3.8.16”。2.71秒!我可以做同样的事情,然后在 Mac 或 Windows 上以同样的方式运行它。这太棒了。

没有缺少 tcl、openssl 或 gzip 的软件包。与其他 Python 源没有冲突。我使用的每个操作系统都不需要不同的范例。没有缺少命令或配置错误PATH。

它之所以能成功,是因为 Astral 利用了一个非常有前途的项目,即python-build-standalone ,并最终获得了它的所有权。这些是无需安装程序即可运行的 Python 构建。该团队不仅大大改进了该项目,而且现在正积极尝试将这些好处贡献给 cPython 上游。事实上,在整个项目过程中,他们都表现出了为邻近的 FOSS 项目做出贡献的意愿。

我发誓,我没有受到他们的赞助!

适合你的项目管理功能
当然,他们还为uv添加了高级项目管理功能,超越了pip和venv。这些功能是可选的,所以你可以按照自己的节奏逐步采用。

  • uv init 不仅会创建一个 .venv 文件夹,还会默认生成一个 pyproject.toml 文件、一个 Git 仓库(带有 Python 专用的 .gitignore 文件)、一个 README.md 文件和一个 hello.py 文件。当然,这些都可以配置。
  • 你可以在 pyproject.toml 中声明你的主要依赖,或者用 uv add 来添加它们。
  • uv remove 会正确地清理你的仓库。
  • uv lock --upgrade-package == 让你可以一次一个版本地小心升级你的包。
  • uv build 会从你的项目中生成一个 .whl 包,但uv并不要求你的项目必须能够被打包。
  • uv run 会在虚拟环境中运行任何命令,即使虚拟环境没有激活。你甚至不需要知道有虚拟环境的存在,也不需要知道“激活”是什么意思。

所有这些命令都会自动且透明地更新锁文件。你不需要时刻盯着你的项目,一切都帮你处理好了。这是因为uv非常快,你甚至感觉不到更新正在发生。你也不需要知道锁文件是什么。

锁文件是跨平台的(这本身就很疯狂!),所以你可以在 Windows 上开发,然后在 Linux 上部署。

出色的性能(再次强调,这是设计的结果,Astral 使用了一些非常有趣的技巧来加速,详见我们的采访)不仅让你感觉毫不费力,还会鼓励你进行实验。你再也不用为尝试新东西付出代价了。你可以在几秒钟内重新开始。

最后但同样重要的一点是工具的可靠性。我数不清有多少次 pyenv、pipenv 或 poetry 在我手上崩溃,给我留下一堆堆栈跟踪去处理。这些工具的粉丝会告诉你他们没遇到过这种情况,但首先,他们在撒谎(我见过有人刚说完几分钟就遇到了!),其次,他们通常只在一两种场景下使用这些工具,所以他们的视角非常有限。

另一方面,uv不仅非常稳定,还具备三种特别罕见且令人向往的品质:

Astral 非常擅长修复 bug。他们倾听反馈,对报告反应迅速,而且非常勤奋。说实话,他们的 bug 跟踪器让人印象深刻。

他们有很好的测试文化。例如,他们有一个非常强大的依赖解析测试套件,并且把它做成了一个独立的包,供其他项目使用。

他们提供了出色的错误信息。看看这个漂亮的依赖解析失败提示:

❯ uv add httpie==2
  × No solution found when resolving dependencies for split (python_full_version >= '3.10'):
  ╰─▶ Because httpie==2.0.0 depends on requests>=2.22.0 and your project depends on httpie==2, we can conclude that your project depends on requests>=2.22.0.
      And because your project depends on requests==1, we can conclude that your project's requirements are unsatisfiable.
  help: If you want to add the package regardless of the failed resolution, provide the <code>--frozen</code> flag to skip locking and syncing.

你可以说这归功于 pubgrub,但他们所有的错误信息都力求如此清晰,而且他们选择依赖时也非常谨慎。

基本上,他们从 pip、rye 和 poetry 中吸取了有效的部分,抛弃了那些没用的东西。然后他们花了几个月时间修复问题,将其提升到了一个极高的质量水平。

这一点不容小觑,因为这种质量和专注在软件中极为罕见,我通常只会将其与 VLC 或 sqlite 这样的项目相提并论。这就是我把 uv 放在的级别。

结果是,当我在培训中将 uv 交给学生时,我几乎不需要做什么工作。我很惊讶地看到他们如何轻松地开始使用它并变得高效,几乎不需要我的指导。我很少需要干预。这是其他工具从未发生过的情况。

在专业项目中,情况略有不同。新项目可以轻松受益于 uv。而遗留项目可能会遇到一些障碍,我们稍后会看到。

那么什么时候应该使用uv,什么时候不应该使用?
基本上,有 5 种情况不应该使用uv:

  1. 您有一个遗留项目,使用uv解决依赖关系不起作用,并且您无法(或不想)为了迁移而清理混乱局面。
  2. 您所在的公司环境不允许您使用它。
  3. 您还不信任它,因为它还不是一个稳定的版本,因为 Astral 尚未发布其商业产品,因为 Rust 贡献者池太小,等等。
  4. 您需要一个未提供的特定版本的 Python uv,并且如果您无法安装 Python,您也不会想使用uv它,尽管它可以与第三方安装的 Python 配合得很好。
  5. 您认为 CLI 对于团队来说太过麻烦。
对我来说,3 和 4 并不是真正的技术问题,因此它们与其说是阻碍因素,不如说是选择。我在这里并不是要说服你做出不同的选择,我对此没有意见,你做你自己。
对于 2 来说,您有很多可以做的事情,因此这一点毫无意义。
这意味着我实际上只需要考虑情况 1 和 5,对此,我只有一条建议:
总是uv先尝试。如果不奏效(这种情况非常罕见),请返回之前的操作或寻找解决方法。

如果 CLI 问题太多,建议使用 python.org 安装程序进行配置,并使用抽象的 IDE 插件uv。但请先尝试一下,会编程的人通常可以学习足够的命令行基础知识来使用 uv。

如果确实不起作用,那么你就转向别的方法。

考虑到使用该工具的绝对好处、采用成本非常低、以及它对您不起作用的可能性更加有限(无论是情况 1、2 还是我不知道的情况;毕竟,我必须假设还有其他我没有遇到的边缘情况),这只是一个不错的选择。

从统计学上来说,大多数时候你都会赢,而这正是你所需要的。