这篇文章摘自Python高效编程实践指南,可在线阅读。
Python 的虚拟环境方案可谓源远流长,种类繁多。如果你接触 Python 已经有一段时间了,那么你很可能听说过 annaconda, virutalenv, venv, pip, pipenv, poetry, pyenv, pyvenv, pyenv-virtualenv, virtualenvwrapper, pyenv-virtualenv wrapper 等相似概念。
在上面这些令人眼花缭乱的词语中,Annaconda(以下简称 conda) 和 Virtualenv 是一对儿对手,Pipenv 则和 Poetry 相互竞争。而 Venv 则是其中血统最为纯正的一个,得到了 Python 官方的祝福。
pipenv 和 poetry,尽管常常被人在讨论虚拟环境的场合下提起,也确实与虚拟环境相关,但他们所做的工作都远远超过了虚拟环境本身——它们的主要功能是提供依赖管理,poetry 还提供了构建和打包功能(我们将在第五章——Poetry 那一章中来详细介绍)。
venv 不是一个独立的工具,它只是一个模块。venv 是从 Python 3.8 起,标准库里提供的一个模块,你可以使用python -m venv
来运行它。它的目标与 virtualenv 比较接近,但只提供了 virutalenv 的一个命令子集。由于它是标准库提供的,因此许多工具,比如 poetry, pyenv 现在都是基于它来构建的。因此,如果你是某个工具的开发者,我想你需要掌握它;否则,你将在使用 poetry 等工具时,自然而然地接触和使用到它,但可能并不知道,幕后英雄其实是 venv。
conda 和 Virtualenv 都是用来创建和管理 Python 虚拟环境的工具,有着相似的命令行接口,不同之处在于:
- Conda 是一个多语言、跨平台的虚拟环境管理器,而 Virtualenv 则只用于 Python。
- 通过 Conda 可以管理(安装、升级)Python 版本,而 virtualenv 则没有这个能力。
- 缺省安装下,conda 会占用大约 100MB 的磁盘空间,而 virtualenv 则只需要占用更少的空间(约 10MB)。这可能既是优势,也是缺点。virtualenv 通过使用对原生库的符号链接来减少对硬盘空间的使用,这使得对原生库的隔离并未真正实现–如果你的应用程序不仅仅依赖 Python 库,还依赖于原生库,则仍然可能产生依赖冲突,导致你的程序出现一些很难查找原因的错误。而在 conda 虚拟环境中,所有的依赖都是完全隔离的。
- 缺省地,conda 对虚拟环境进行集中式管理,所有的虚拟环境都在一个目录下,而 virtualenv 则倾向于将虚拟环境放在当前目录下。长期来看,非集中式管理可能导致这些虚拟环境呈碎片化而难于被追踪。
上述第 3 点可能是最重要的差异。我们很难保证 Python 应用程序永远只依赖于纯的 Python 库。事实上,一些性能相关的模块,往往是用 c++或者其它语言来开发的。Lapack(一个常用的线性代数库,Python 中最著名的科学计算库 Numpy 和 scipy 都依赖于此)或者 OpenSSL 都是常见的例子。
在本书中,我们只推荐使用 Annaconda。但对 virtualenv 和 venv,读者需要知道的是,如果正在开发一个生成和构建虚拟环境的工具(或者模块)—— 比如,为一个容器构建一个虚拟环境,或者为分布式程序动态构建一个远程的虚拟环境–那么 venv 或者 virtualenv 将是不二之选,因为 conda 并不是一个轻量级的工具。
对上面没有提到的那些技术,我们将不会在本书中详细介绍它,这里仅对它们做一个概括性的描述:
- pyenv 是一个脚本,不能在 windows 环境下使用。它的作用是拦截你对 python 工具链的调用,为你选择正确的 python 版本。此外,你也可以使用它来安装多个版本的 python。它的功能完全可以诸如 annaconda 之类的工具替代。但如果你使用 virtualenv 的话,那么很有可能你仍然需要使用 pyenv 来安装和选择 python 版本。