Python 诞生三十余年,但在它的生态里,如何优雅地管理依赖和环境始终是一条漫长的探索之路。
从 2004 年 easy_install 的横空出世,到今天集大成的 uv,无数开发者在“依赖地狱”与“环境隔离”之间寻找平衡。
这篇文章想和你一起回顾过去二十年里 Python 依赖与环境管理工具的迭代,也分享我个人在这些工具之间摸索的心路历程。
自动包管理工具的先驱:easy_install
在一切规范化工具出现之前,Python 的包管理是相当原始的。开发者们需要把第三方库的源码下载下来,手动放到项目目录里。
为了解决自动安装包的问题,easy_install 应运而生。
2004年:easy_install——从 0 到 1 的突破
easy_install 是 Python 包管理的早期自动化解决方案。它可以从 PyPI 自动下载并安装包,极大地简化了获取第三方库的流程。然而,它也存在很多问题:
- 无法直接卸载:安装容易,卸载却需要手动删除文件。
- 无依赖管理:它会安装包及其所有依赖,但无法记录或锁定这些依赖的精确版本,导致“依赖地狱”问题依然存在。
- 容易冲突:多个项目依赖同一个库的不同版本时,easy_install 会陷入困境。
虚拟环境管理+更智能的包管理:virtualenv/venv,pip
2008年:virtualenv——为每个项目建一个虚拟环境
virtualenv 的出现是一个里程碑。它创造性地提出可以为每个项目创建一个独立的、隔离的 Python 虚拟环境。在这个虚拟环境里,你可以随心所欲地安装任何版本的包,而不会影响到系统全局或其他项目。virtualenv 解决了项目间的环境冲突问题,为后续的工具发展奠定了基础。
2011年:pip——更智能的包安装器
pip 作为 easy_install 的替代品逐渐成熟,并最终成为 Python 事实上的标准包安装器。它解决了 easy_install 的诸多痛点:
-
可以一条命令卸载包。
pip uninstall package_name
-
支持依赖管理:能够自动处理依赖关系。
-
引入 requirements.txt:通过一个简单的文本文件,你可以记录项目所需的所有依赖及其精确版本。其他人拿到项目后,只需运行
pip install -r requirements.txt
就能复刻你的开发环境。
2012年:venv——Python内置的虚拟环境工具
venv 是 Python 3.3 引入的一个标准库模块,它提供了 virtualenv 的核心功能,但更加轻量和易用。你可以通过
python -m venv my_env
来创建一个新的虚拟环境,而无需额外安装任何东西。
早期版本的venv相比virtualenv,缺少很多高级特性,因此很多开发人员仍然选择继续使用virtualenv。但随着Python的发展,venv也越来越成熟,目前已经取代了virtualenv成为了虚拟环境的事实性官方标准。
Python解释器版本管理工具:pyenv
pip 和 virtualenv/venv 解决了“包”和“环境”的问题,但还有一个更底层的问题:Python 解释器本身呢?如果你的电脑系统自带了 Python 2.7,但你的新项目需要 Python 3.10,而另一个维护中的老项目又需要 Python 3.3,怎么办?手动安装、修改 PATH?太麻烦了。
2011年:pyenv——掌控你的 Python 版本
pyenv 的出现,完美地填补了这个空白。它深受 Ruby 社区的 rbenv 启发,其核心思想非常巧妙:它并不真正地“安装”多个 Python 版本,而是在你的 PATH 路径最前面插入一个“垫片”(shim)。当你调用 python 命令时,这个垫片会根据你当前目录或全局的配置,智能地转发给对应版本的 Python 解释器。
通过
pyenv install 3.10.0
命令,你可以轻松安装任意版本的Python(此处示例3.10.0)
通过
pyenv local 3.8.5
命令,你可以为当前目录下的项目指定使用任意版本的Python(此处示例3.8.5)
pyenv 解决了 Python 解释器版本管理的难题,它与 pip 和 venv 形成了三件套:pyenv 负责管理解释器版本,venv 负责创建隔离环境,pip 负责安装依赖包。
一体化工具的尝试:pipenv和poetry
pyenv + virtualenv + pip 虽然强大,但毕竟需要操作三个工具。开发者们开始向往一个能“一键搞定所有”的解决方案。于是,一系列“All-in-One”工具应运而生。
2017年:Pipenv——官方推荐的“希望”
Pipenv 由 Requests 库的作者 Kenneth Reitz 主导开发,并一度被 Python 官方推荐为“用于 Python 项目的官方依赖管理工具”。它试图将 pip 和 venv 的功能合二为一。
它用 Pipfile 和 Pipfile.lock 替代了 requirements.txt,提供了更精确的依赖锁定和开发/生产环境的区分。
同时,Pipenv 在早期因为一些性能问题、锁文件生成缓慢以及偶尔的 Bug,社区评价褒贬不一,逐渐失去了一些光环。
Pipenv 本身不管理 Python 解释器版本。所以pyenv在管理不同Python版本的多个项目时仍是必需的工具。(笔者并没有真正使用过pipenv这个工具,根据网上的资料查询得出这个结论,不太确定是不是真的没有这个功能。如果有误,请不吝赐教)
2018年:Poetry——更现代的依赖管理工具
几乎与 Pipenv 同期,Poetry 横空出世,并迅速赢得了大量开发者的心。
- 它使用 pyproject.toml 作为唯一的配置文件,这是 PEP 518 和 PEP 621 所倡导的现代 Python 项目标准,非常简洁和强大。
- 它的依赖解析算法和锁文件(poetry.lock)生成速度比 Pipenv 更快、更可靠。
- 它集成了构建、打包和发布到 PyPI 的功能,真正实现了从开发到部署的全流程管理。
和pipenv一样,Poetry自身不负责Python版本的管理,仍然需要搭配pyenv来管理Python解释器版本。(笔者并没有真正使用过poetry这个工具,根据网上的资料查询得出这个结论,不太确定是不是真的没有这个功能。如果有误,请不吝赐教)
另一条路:科学计算领域的王者——Conda
在主流 Python 社区为 pip 和 virtualenv 演进时,科学计算领域走出了另一条完全不同的道路。
2012年:Conda——安装依赖、Python版本管理全包了
Anaconda是数据科学领域发展出的包管理+Python版本管理工具。而且它管理的不仅仅是 Python 包,还可以是R语言等其他语言的软件包。此外,为了提供开箱即用的机制,Anaconda会默认安装许多常用的科学计算库,但这也导致了安装体积过大。因此,又推出了miniconda这个精简版,它只包含了最基本的 Python 和 conda 包管理器。对于Python开发人员来说,更多使用的还是miniconda。
Anaconda 在安装时就会自带一个稳定版本的Python,同时还可以通过conda命令直接安装其他版本的Python。
conda create -n myenv python=3.9
这条命令,就可以创建一个包含 Python 3.9 的新环境。
Anaconda可以不依赖pip,直接通过 conda install
命令安装包。但是conda安装的包版本常常会和pip包冲突,而且PyPI上的很多包都没有conda的版本。
另外,Anaconda使用environment.yml文件来描述环境,这个文件类似于requirements.txt,但更加复杂。在conda中,通过yaml文件来创建环境的命令为:
conda env create -f environment.yml -n 环境名
但说实话能够一次性成功配置环境属于少数情况,一般都会遇到配置太慢、卡死、solving environment failed、PackageNotFound、以及pip爆出的一堆红字。
综合上述原因,在实际的工作流中,人们通常会使用conda创建一个干净的虚拟环境,然后再在这个虚拟环境中使用pip安装其他依赖。
conda create -n myenv python=3.9
conda activate myenv
pip install -r requirements.txt
这也是现在科研领域使用Python的主要方式,绝大多数的Python科研项目都是这样安装依赖的。另外一些老的软件开发项目也会使用这种方式。VSCode对于conda的兼容性也很好,可以直接检测出conda管理的虚拟环境。
速度与整合的终极追求:uv 的时代
时间来到最近,一个名为 uv 的工具横空出世,以其惊人的速度和“大一统”的雄心,再次搅动了整个生态。
2023年:uv ——极速的全面解决方案
uv 由 Astral(Ruff 的开发公司)发布,它是一个用 Rust 编写的、极其快速的 Python 包安装器,最初旨在成为 pip 的直接替代品。
使用
uv pip install package_name
命令,可以极大地提升安装速度。它的速度优势是颠覆性的,将依赖解析和安装的时间从分钟级缩短到了秒级。
但uv 的目标远不止于作为一个快速的pip替代品,它正在迅速整合 Python 项目管理的所有核心能力:
- 项目管理:
uv init
命令可以快速创建一个包含pyproject.toml
的项目骨架。 - 虚拟环境管理:
uv venv
可以创建和管理虚拟环境。 - 依赖解析与安装:
uv add
、uv remove
和uv sync
等命令提供了原生的依赖安装体验 - Python 版本管理:可以通过
uv python install
命令安装指定的Python版本
现在仅使用uv一个工具就可以实现原本需要pip,venv,pyenv三个工具才能实现的功能。而且相比conda,其更符合Python标准,更加Pythonic。
笔者个人使用经历和体会
前面这段是对历史的梳理,现在来谈一谈我个人使用Python依赖管理工具的经历和体会。
本科毕业后,我先从事了两年NodeJS开发的工作。我个人感觉相对来说NodeJS的版本兼容性应该比Python好不少吧?当时压根就没想到需要不同的NodeJS版本来管理不同项目的问题,用我电脑上安装的NodeJS LTS(长期支持版)运行公司的各个项目都没有遇到兼容性问题。另外,NodeJS中使用npm工具管理项目依赖包,每个项目就是一个独立的环境,也不会出现不同项目之前依赖包冲突的问题。虽然现在也出现了nvm这个管理不同Nodejs版本的工具,但这个工具只是锦上添花,在大多数情况下并不是必需的。
但读研以后开始使用Python,整个情况就变了。不同版本的Python之间兼容性很差,只安装一个Python版本完全无法应对不同的项目,而且pip安装依赖在没有虚拟环境的情况下,默认是到全局环境,无法进行不同项目的环境隔离。
conda是我最早接触的工具,因为我是读研后才开始使用Python的,一开始主要做的也是科研项目。实验室的师兄师姐教我们就是直接用conda,而且基本上所有的科研论文项目的主页上也都是用的conda。venv作为Python官方的虚拟环境解决方案我也了解过,但还是不如conda方便,基本没用过。有了conda以后,项目的版本依赖管理就变得清晰了很多,而且在conda里面想用哪个版本的Python就可以用哪个版本的Python。
conda自带的 conda install
命令在很多时候安装不到想要的包,而且速度很慢。所以我都是先用conda安装虚拟环境,再用pip安装依赖。
假如我想导出环境给另一台电脑使用该怎么办呢?一开始使用的是这个命令:
pip freeze > requirements.txt
但是这样会存在一个问题,导出的文件包含的是当前虚拟环境中所有的包。有的时候为了图省事,一个conda虚拟环境会给多个项目使用,这样就可能包含很多用不着的包。为了解决这个问题,我又找到了pipreqs这个工具,该工具会扫描当前项目下实际使用的依赖包,并生成对应的requirements.txt文件。
尽管pipreqs工具可以导出实际需要的依赖,但仍然需要手动导出。但使用过npm的我还是觉得不太方便,为什么就不能在安装的同时直接生成一个类似于package.json的文件来管理依赖呢?(其实pyproject.toml文件早已出现,但由于读研期间把绝大多数的精力都放在读论文,想科研点子上,没有时间学习开发工具的使用,一直活在自己的信息茧房里,也就不知道这个东西的存在)
一直到了研究生毕业,再次工作以后,我接触了Dify项目,发现其中使用了一种新的依赖管理工具uv,而且使用pyproject.toml管理项目依赖包。这不就是我梦寐以求的工具吗?再去回看历史,发现原来之前还有poetry,pipenv这些工具。而uv基本上解决了之前所有工具的问题。现在的Python开发人员真是身处一个好时代,有uv这么好的工具。
最后说一下工具的选型
对于科研人员来说,还是推荐使用conda。尽管其比较笨重,但使用方便,而且也是科研领域的主流解决方案。
但对于开发人员来说,强烈建议转向uv这个现代化工具。这是目前Python依赖管理的集大成者。
标题:Python 包与环境管理简史:从混乱到优雅
作者:aopstudio
地址:https://neusoftware.top/articles/2025/09/18/1758169543323.html