Python虚拟环境是一个自包含的目录,包括自己的Python解释器和一组已安装的包,与系统范围的Python安装隔离。使用虚拟环境让每个项目可以维护自己的依赖项,而不会影响同一台机器上的其他项目。

本指南介绍如何使用venv(Python 3内置)和virtualenv(流行的第三方替代方案)在Linux和macOS上创建和管理虚拟环境。

快速参考

任务                                          命令
安装venv支持 (Ubuntu, Debian)               sudo apt install python3-venv
创建环境                                   python3 -m venv venv
激活 (Linux / macOS)                           source venv/bin/activate
取消激活                                   deactivate
安装包                                     pip install package-name
安装特定版本                               pip install package==1.2.3
列出已安装包                                pip list
保存依赖                                   pip freeze > requirements.txt
从requirements文件安装                          pip install -r requirements.txt
使用特定Python版本创建                       python3.11 -m venv venv
创建时包含系统包                            python3 -m venv --system-site-packages venv
创建时升级核心venv依赖                      python3 -m venv --upgrade-deps venv
安装virtualenv                               pipx install virtualenv
将pipx工具添加到PATH                         pipx ensurepath
全局安装CLI工具                           pipx install <tool>

什么是Python虚拟环境?

当你使用pip install全局安装一个包时,它对系统上的每个Python脚本都可用。当两个项目需要同一个库的不同版本时,这就成了问题。例如,一个项目要求requests==2.28.0,而另一个项目要求requests==2.31.0,两者无法同时全局安装。

虚拟环境通过为每个项目提供独立的包存储空间来解决这个问题。激活环境后,它会将其bin/目录添加到你的PATH前面,这样pythonpip就会解析到环境内的版本,而不是系统范围的版本。

externally-managed-environment错误

在Ubuntu 23.04及更高版本以及Debian 12及更高版本上,系统Python根据PEP 668被标记为外部管理。如果你在虚拟环境外运行pip install,命令会报错停止:

error: externally-managed-environment

× This environment is externally managed
╰→ To install Python packages system-wide, try apt install
    python3-xyz, where xyz is the package you are trying to
    install.

这是故意设计的,不是bug。发行版拥有系统Python,允设pip写入可能会破坏依赖特定库版本的打包工具。你可以使用--break-system-packages强制安装,但更安全的做法是本指南介绍的:创建虚拟环境并在其中安装。

安装venv

venv模块随Python 3一起发行,在大多数系统上无需单独安装。在Ubuntu和Debian上,该模块被单独打包:

sudo apt install python3-venv

在Fedora、RHEL及其衍生版本上,venv默认包含在Python包中。

创建环境前先验证Python版本:

python3 --version

创建虚拟环境

进入你的项目目录并运行:

python3 -m venv venv

第二个venv是将被创建的目录名称。常见的命名习惯是venv.venv。该目录包含Python二进制文件或符号链接、激活脚本、pip和用于安装包的site-packages目录。

要在特定位置创建环境而非当前目录:

python3 -m venv ~/projects/myproject/venv

venv常用参数

python3 -m venv接受几个有用的参数:

--system-site-packages — 让环境可以看到系统Python中安装的包。当重量依赖更容易通过系统包管理器安装时很有用。

--without-pip — 跳过捆绑的pip。你可以稍后用python -m ensurepip安装pip。

--copies — 将Python二进制文件复制到环境中而不是创建符号链接。默认使用符号链接,速度更快但将环境绑定到原始解释器路径。

--upgrade-deps — 创建后立即将核心venv依赖项(如pip)升级到PyPI上的最新版本。

--upgrade — 当系统Python升级时,使用新的Python版本重建环境。运行python3 -m venv --upgrade /path/to/existing/venv

开始新项目时的常见组合用法:

python3 -m venv --upgrade-deps myenv

激活虚拟环境

使用环境前需要先激活它。在Linux和macOS上:

source venv/bin/activate

如果你使用fish或csh,请同样目录下的activate.fishactivate.csh。在Windows上,激活脚本位于venv\Scripts\activate(cmd)或venv\Scripts\Activate.ps1(PowerShell)。

激活后,shell提示符会显示环境名称:

(venv) user@host:~/myproject$

此时pythonpip指向虚拟环境内的版本,而非系统范围的版本。

要取消激活并返回系统Python:

deactivate

pyvenv.cfg文件

每个环境根目录包含一个pyvenv.cfg文件,记录了构建环境所用的解释器、Python版本和系统站点包控制标志:

home = /usr/bin
include-system-site-packages = false
version = 3.12.3

如果需要在不重建环境的情况下切换系统包访问权限,将include-system-site-packages编辑为true。其他设置不应手动修改,因为环境重建时会重新生成它们。

安装包

激活环境后,像平时一样使用pip安装包。

pip install requests

安装特定版本:

pip install requests==2.31.0

列出当前环境安装的所有包:

pip list

此处安装的包与系统及其他虚拟环境完全隔离。

使用requirements.txt管理依赖

与他人分享项目或部署到另一台机器时,需要一种方式来复现相同的包版本。常规做法是将所有依赖保存到requirements.txt文件:

pip freeze > requirements.txt

该文件列出每个已安装的包及其精确版本:

certifi==2024.2.2
charset-normalizer==3.3.2
idna==3.6
requests==2.31.0
urllib3==2.2.1

在新环境中从文件安装所有包:

pip install -r requirements.txt

这是在不同机器或CI/CD管线中复现环境的标准工作流。

使用特定Python版本

默认情况下,python3 -m venv使用系统默认的Python 3版本。如果安装了多个Python版本,可以指定使用哪个:

python3.11 -m venv venv

这将基于Python 3.11创建环境,无论系统默认版本是什么。检查可用版本:

python3 --version
python3.11 --version

virtualenv:venv的替代方案

virtualenv是一个比venv更早出现的第三方包,提供额外的环境创建功能。使用pipx作为隔离的命令行工具安装:

pipx install virtualenv

使用virtualenv创建和激活环境的方式相同:

virtualenv venv
source venv/bin/activate

使用特定的Python解释器:

virtualenv -p python3.11 venv

当你频繁创建环境并希望利用其缓存的种子包、解释器发现功能或编程API和插件系统时,选择virtualenv。与venv不同,virtualenv可以通过版本规范符查找已安装的解释器,并且独立于Python发行版本更新。

对于大多数现代Python 3项目,venv已经足够,且无需安装。

uv:更快的现代替代方案

uv是一个用Rust编写的更新的Python包管理器,包含内置的venv命令。它在环境创建和包安装方面明显快于venvvirtualenv

使用uv创建环境:

uv venv myenv
source myenv/bin/activate

uv在CI中安装速度很重要时成为常见选择,但venv在希望零额外依赖时仍是最佳默认选择。

使用pipx安装工具

有时你希望全局安装一个Python工具,让它始终可用,但不污染系统Python或创建项目级venv。pipx通过为每个工具提供私有的虚拟环境来解决这个问题,你不需要激活它。

安装pipx并用它安装如httpie等CLI工具:

sudo apt install pipx
pipx ensurepath
pipx install httpie

运行pipx ensurepath后重启shell,以使pipx安装的命令在PATH上可用。

venv管理项目依赖,用pipx管理命令行工具。两者解决不同的问题。

从版本控制中排除环境

虚拟环境目录不应提交到版本控制。它体积大、与机器相关且可从requirements.txt完全复现。将其添加到.gitignore

echo "venv/" >> .gitignore

如果环境命名为.venv,则将.venv/添加到.gitignore

常见问题排查

执行python3 -m venv venv报错"No module named venv"

在Ubuntu和Debian上,venv模块不包含在基础Python包中。使用sudo apt install python3-venv安装,然后重试。

pip install将包安装到全局而非环境中

环境未激活。先运行source venv/bin/activate。可以通过which pip验证,它应指向venv/目录内的路径。

激活后python仍指向环境外

环境可能未激活,或shell缓存了旧的命令路径。运行source venv/bin/activate,然后检查which pythonwhich pip。在Bash或Zsh中,如果shell仍解析旧路径,运行hash -r

移动或重命名目录后环境损坏

虚拟环境包含Python解释器的绝对路径。移动或重命名目录会使这些路径失效。删除目录并在新位置重建环境,然后从requirements.txt重新安装。

常见问题

venv和virtualenv有什么区别?

venv是Python 3标准库模块,无需安装。virtualenv是第三方工具,具有缓存环境创建、解释器发现、编程API和插件支持。对于基本环境需求的新Python 3项目,推荐使用venv

为什么pip说环境是externally managed?

Ubuntu 23.04及更高版本和Debian 12及更高版本根据PEP 668将系统Python标记为外部管理,因此pip拒绝向其安装。创建虚拟环境并在其中安装。仅在你了解后果时才使用--break-system-packages

应该将虚拟环境提交到git吗?

不应该。将venv/(或.venv/)添加到.gitignore,只提交requirements.txt。任何人结账后可以用pip install -r requirements.txt重新创建环境。

每个项目都需要虚拟环境吗?

强烈建议。没有隔离环境,为一个项目安装或升级包可能会破坏另一个。创建虚拟环境的开销很小。

pip freeze和pip list有什么区别?

pip list以人类可读格式显示已安装包。pip freezerequirements.txt格式(package==version)输出,适合与pip install -r配合使用。

能否使用与系统默认不同的Python版本创建虚拟环境?

可以。创建环境时传递所需解释器的路径:python3.11 -m venv venv。环境将使用该解释器执行pythonpip命令。

对于black、ruff、httpie等CLI工具应该用venv还是pipx?

使用pipx。它为每个工具提供私有环境,安装不会冲突,且你无需激活任何东西就能运行工具。将venv留给项目导入的库。

pyvenv.cfg是做什么的?

它是每个venv根目录的小配置文件。记录环境构建所用的解释器、Python版本以及环境是否可以看到系统站点包。include-system-site-packages标志是通常需要手动编辑的唯一设置。

总结

虚拟环境是管理Python项目依赖的标准方式。使用python3 -m venv venv创建,source venv/bin/activate激活,并使用pip freeze > requirements.txt捕获依赖项。