Python 版本管理

Python的版本管理是在实践中一定会面对的问题。Pyenv是一个简单的Python版本管理程序。使用Pyenv可以在多个Python版本间进行切换。本文主要参考项目文档进行翻译和编写。大概的使用效果如下图所示:

Pyenv可以做什么…

  • 允许您根据每个用户更改全局Python版本。
  • 提供对每个项目Python版本的支持。
  • 允许用环境变量覆盖Python版本。
  • 一次从多个版本的Python中搜索命令。这有助于使用tox跨Python版本进行测试。

与pythonbrew和pythonz相比,Pyenv不能做什么…

  • 取决于Python本身。Pyenv是由纯shell脚本构成的。Python不存在引导问题。
  • 需要加载到shell中。相反,Pyenv的接入通过在PATH中添加一个目录来工作。
  • 当然,可以创建viralenv,或者创建pyenv-viralenv来自动化这个过程。但管理会比较繁琐,并容易产生混乱。

Pyenv如何工作

在高级别上,Pyenv使用注入到PATH中的可执行文件拦截Python命令,确定应用程序指定了哪个Python版本,并将命令传递到正确的Python安装。

理解Pyenv的Shims

Pyenv的工作原理是在PATH前面插入一个shims目录来工作:

1
$(pyenv root)/shims:/usr/local/bin:/usr/bin:/bin

通过一个称为重拼凑的过程,Pyenv在该目录中维护shims,以匹配每个已安装版本Python的命令,python、pip等。

Shims是轻量级的可执行文件,只需将命令传递给Pyenv即可。因此,安装了Pyenv之后,当运行pip时,操作系统将执行以下操作:

  • 在PATH中搜索名为pip的可执行文件。
  • 在PATH的开头找到名为pip的Pyenv shim。
  • 运行名为pip的shim,然后将命令传递给Pyenv。

理解Python版本选择

当执行一个shim时,Pyenv通过从以下来源读取它来决定使用哪个Python版本,顺序如下:

  1. PYENV_VERION环境变量(如果指定)。您可以使用Pyenv shell 命令在当前shell会话中设置这个环境变量。
  2. 当前目录中应用指定的 .python-version 文件(如果存在)。可以使用 Pyenv shell 命令修改当前目录的 .python-version 文件。
  3. 通过搜索每个父目录找到第一个 .python-version 文件(如果有的话),直到文件系统的根目录。
  4. 全局 $(Pyenv root)/version 文件。可以使用 Pyenv global命令修改这个文件。如果没有全局版本文件,pyenv 假设想要使用“系统” Python (见下文)。

一个特殊的版本名称“system”意味着在PATH中shims的条目之后找到的任何Python(换句话说,如果Pyenv shims不在PATH中,将运行PATH中找到的Python)。请注意,Pyenv认为这些安装不在其控制范围之内,并不试图以任何方式检查或区分它们。因此,例如,如果你在MacOS上并且有OS绑定的Python 3.8.9和Homebrew安装的Python 3.9.12和3.10.2 – 对于Pyenv来说,这仍然是一个单独的“system”版本,并且无论哪一个是在PATH指定的第一个可执行文件名,它都将被运行。

注意: 可以同时激活多个版本,包括同时激活Python2或Python3的多个版本。这允许并行使用Python2和Python3,并且是类似tox这样的工具所需要的。例如,要指示Pyenv首先使用系统Python和Python3(例如2.7.9和3.4.2),但同时使用Python 3.3.6、3.2.1和2.5.2,首先执行pyenv install安装缺少的版本,然后设置pyenv global system 3.3.6 3.2.1 2.5.2。然后就可以使用适当的pythonX或pythonX.Y名称来调用这些版本中的任何一个。也可以手动在 .python-version 文件中指定多个版本,用换行符分隔。以 # 开头的行将被忽略。

pyenv which 显示通过一个shim调用时将运行哪个真正的可执行文件。例如,如果已经安装了3.3.6、3.2.1和2.5.2,其中选择了3.3.6和2.5.2,并且系统Python是3.2.5,pyenv which python2.5应该显示$(Pyenv root)/version/2.5.2/bin/python2.5,pyenv which python3 – $(Pyenv root)/version/3.3.6/bin/python3和pyenv which python3.2 – 由于穿透指向系统Python(见下文)。

如果在所选的Python安装中没有出现相应的可执行文件,那么会穿透到在PATH中相关的可执行文件。这允许使用系统上其他地方安装的任何程序,只要它们没有被选定的Python安装遮蔽。

由Pyenv提供安装Python的位置

一旦pyenv确定了应用程序指定的Python版本,它就会将命令传递给相应的Python。
每个Python版本都安装到$(Pyenv root)/versions下自己的目录中。
例如,可能已经安装了以下版本:

  • $(pyenv root)/versions/2.7.8/
  • $(pyenv root)/versions/3.4.2/
  • $(pyenv root)/versions/pypy-2.4.0/

就Pyenv而言,版本名就是$(Pyenv root)/version下的目录。

安装

在Linux类系统下用自动安装程序可以很简单的完成安装:

1
curl https://pyenv.run | bash

更多详情请访问项目:https://github.com/pyenv/pyenv-installer

注意,出于某种原因,自动安装程序可能会出现好像卡死的现象,多尝试几次即可。

设置Pyenv的shell环境

对于bash:

Bash启动文件在不同的发行版之间差异很大,它们的来源、在什么情况下、以什么顺序,以及它们执行什么附加配置。因此,在所有环境中获取Pyenv的最可靠方法是将Pyenv配置命令追加到 .bashrc(用于交互式shell)和Bash将使用的配置文件(用于登录shell)。

首先,通过在终端中运行以下命令将命令添加到 ~/.bashrc:

1
2
3
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc

然后,如果有 ~/.profile、~/.bash_profile或 ~/.bash_login,也将命令添加到那里。如果没有这些文件,请将它们添加到 ~/.profile。

  • 添加到 ~/.profile:
1
2
3
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init -)"' >> ~/.profile
  • 添加到 ~/.bash_ profile:
1
2
3
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
echo '[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile

重启shell

使PATH更改生效。

1
exec "$SHELL"

安装Python构建依赖

在尝试安装新的Python版本之前需要先安装构建Python的依赖。

对于Ubuntu/Debian:

1
2
3
sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl git \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

使用

安装其他Python版本

要安装其他Python版本,请使用pyenv install
运行pyenv install -l提供所有可用版本的列表。
例如,要下载并安装Python 3.13.1,运行:

1
pyenv install 3.13.1

注意: 大多数Pyenv提供的Python版本都是源代码版本,并且是从源代码构建的,作为安装的一部分(这就是为什么需要预安装Python构建依赖)。你可以给Python的configure和编译器标志传递选项来自定义构建,详细信息请参阅Special environment variables in Python-Build’s README

注意: 如果在安装Python版本时遇到困难,请访问wiki页面:Common Build Problems

注意: 如果希望以较长的构建时间为代价获得更快的解释器,请参阅Building for maximum performance in Python-Build’s README

自动解析最新版本的前缀

除uninstall外,所有Pyenv子命令都会自动解析相应版本行中最新版本的完整前缀。
pyenv install选择已知的最新版本,而其他子命令选择已安装的最新版本。例如,安装,然后切换到最新的3.13.1版本:

1
2
pyenv install 3.13.1
pyenv global 3.13.1

可以运行pyenv latest -k 来查看pyenv install将如何解析特定的前缀,或者运行pyenv latest 来查看其他子命令将如何解析它。
有关详细信息,请参阅pyenv最新文档

具有扩展支持的Python版本

对于以下Python版本,Pyenv应用了用户提供的补丁,这些补丁为一些较新的环境添加了支持。虽然没有积极地维护这些补丁,因为现有的版本从来没有更改过,但可以肯定的是,它们将继续工作,直到这些环境的后续版本中出现更多不兼容的更改。

  • 3.7.8-3.7.15、3.8.4-3.8.12、3.9.0-3.9.7:XCode 13.3
  • 3.5.10、3.6.15:MacOS 11+和XCode 13.3
  • 2.7.18:MacOS 10.15+和Apple Silicon

在Python版本之间切换

要选择Pyenv安装的Python作为要使用的版本,请运行以下命令之一:

  • pyenv shell 仅为当前shell会话选择。
  • pyenv local 无论何时,只要在工作目录(或者它的子目录)中,就会自动选择。
  • pyenv global 为用户帐户全局选择。

例如,选择上面提到的新安装的Python 3.13.1作为首选版本:

1
pyenv global 3.13.1

现在,无论何时调用python、 pip等,都将运行来自Pyenv提供的3.13.1安装的可执行文件,而不是系统Python。

使用“system”作为版本名称将把选择重置为系统提供的Python。

请参阅Understanding shimsUnderstanding Python version selection,以获得有关选择如何工作的更多细节和有关其用法的更多信息。

卸载Python版本

随着时间的推移,将在$(Pyenv root)/versions目录中累积Python版本。
要删除旧的Python版本,使用pyenv uninstall
或者,可以简单地rm -rf要删除的版本的目录。可以使用pyenv prefix命令找到特定Python版本的目录,例如:pyenv prefix 2.6.8。但是请注意,插件可能会在卸载时运行额外的操作,这也需要手动完成。例如,Pyenv-Virtualenv 还删除了与正在卸载的版本相关的所有虚拟环境。

其他操作

运行pyenv commands获取所有可用子命令的列表。使用–help运行一个子命令以获得有关它的帮助,或者查看Commands Reference
注意,安装的Pyenv插件可以添加它们自己的子命令。

使用安装程序升级

如果用Pyenv安装程序安装了Pyenv,就已经有了可以升级Pyenv和所有已安装插件的Pyenv-Update插件:

1
pyenv update