专栏首页Coder Sam的专栏pyenv 神器原理分析
原创

pyenv 神器原理分析

pyenv 是什么

  • Python 多版本及虚拟环境管理器,支持:
    • 使用与系统不同的 Python 版本或虚拟环境
    • 每个项目使用不同的 Python 版本或虚拟环境
    • 通过环境变量切换不同的 Python 版本或虚拟环境
    • 同时使用多个 Python 版本或虚拟环境的命令
    • ……

pyenv 干什么

解决两种场景的问题……

场景一:一台机器同时安装 Python 2.6、2.7、3.8

一个传统的方案是每个版本的 Python 可执行文件使用不同的名字,如 python、python2.6、python3。

image.png

这种方案需手动指定python版本,使用起来很不方便:

python manage.py runserver

python3 manage.py runserver

python2.6 manage.py runserver

场景二:一台机器同时使用同一个 Python 库的不同版本

这个场景的典型工具为 virtualenv 和 pyvenv(各工具介绍见《一文了解virtualenv、pyvenv、pyenv、pyenv virtualenv》)。但使用时需要手动激活和注销要使用的虚拟环境,比较麻烦。

image.png

使用 pyenv 之后

# 安装各版本的 Python
pyenv install 2.7.17
pyenv install 3.7.6
pyenv install 3.8.2

# 创建各版本对应的虚拟环境
pyenv virtualenv 2.7.17 venv2
pyenv virtualenv 3.8.2 venv3

# 使用 Python 版本或虚拟环境
pyenv global 2.7.17	# 所有项目默认使用 Python 2.7.17
pyenv local 3.8.2	# 本目录及子目录使用 Python 3.8.2
pyenv local venv2	# 本目录及子目录使用基于 Python 2.7.17 的虚拟环境 venv2
pyenv shell venv3	# 当前 shell 临时使用基于 Python 3.8.2 的虚拟环境 venv3

更重要的是,pyenv 使用了垫片的原理,使用某个 Python 版本或虚拟环境完全是自动的,无需手动指定。例如上面例子设置了 pyenv local venv2,那么进入该目录及其子目录,自动使用的就是基于 Python 2.7.17 的虚拟环境 venv2,而离开该目录后又自动切换到其他 Python 版本或虚拟环境了。

pyenv 执行命令原理

有位伟人说过:

Any problem in computer science can be solved by another layer of indirection.
——计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。

pyenv 就是使用了中间层的原理来实现的的,即 shims/垫片。

初始化 pyenv

安装 pyenv 后,需要在当前 shell 的配置文件(bash 为 ~/.bashrc,zsh 为 ~/.zshrc 等等)中增加相应命令:

# vim ~/.bashrc
export PATH="/data/sammyshen/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

这几个命令在每次登陆 shell 时,会更改 PATH 环境变量,将 pyenv 的路径加入到 PATH 环境变量前面。例如:

image.png

shims/垫片的简化基本原理

Linux 执行命令时,是依次遍历 PATH 环境变量的每个路径,查找所执行的命令。当在某个目录下找到第一个匹配时即停止遍历,所以 PATH 环境变量中,前面的路径比后面的路径具有更高的优先级。

这是垫片原理的一个简化示例:

image.png

可以看到,在修改 PATH 之前,python 命令使用的是 /usr/bin/python。但通过 export PATH=$PWD:$PATH 将当前路径加入到 PATH 环境变量前面后,python 命令使用的就是当前目录下名为 python 的脚本了。

pyenv 在 ~/.pyenv/shims 目录下创建了各种 python 相关命令的垫片(~/.bashrc 中加入的命令调用 pyenv-rehash 生成的,pyenv install 命令也会调用 pyenv-rehash 进行更新):

image.png

所以当我们执行 python 相关的命令时,实际执行的是这些垫片。

这些垫片的内容都是相同的:

image.png

从脚本内容可以看出,当我们执行某个命令 program "param1" "param2" ……时,实际执行的是 pyenv exec "program" "param1" "param2" ……。

例如执行 python -V,实际执行的是 pyenv exec python -V。

确定版本号

在 pyenv-exec 命令中,首先会调用 pyenv-version-name 确定 python 版本或虚拟环境版本,具体查找规则为:

image.png

确定与版本号对应的可执行文件

在 pyenv-exec 命令中,会再调用 pyenv-which 确定可执行文件 program 的路径。如果前面 pyenv-version-name 确定了 python 版本或虚拟环境版本,则使用 <pyenv 安装路径>/versions/<版本号>/bin/<程序名> 或 <pyenv 安装路径>/versions/<版本号>/env/<虚拟环境名>/bin/<程序名>,否则遍历所有版本号的安装路径,按顺序取第一个匹配到的可执行文件。

执行命令

确定与版本号对应的可执行文件路径 path 之后,执行以下命令:

exec -a program "$path" "param1" "param2" ……

(注:即执行 "$path" "param1" "param2",并使用 program 作为程序名,程序名即 shell 中的 $0,python 中的 sys.argv0)

例如执行 python -V,确定 pyenv 版本为 2.7.17,对应可执行文件为 ~/.pyenv/versions/2.7.17/bin/python,则执行命令为:

exec -a python ~/.pyenv/versions/2.7.17/bin/python -V

以上就是 pyenv 执行命令的基本原理了。

pyenv 版本管理原理

pyenv 管理版本主要使用三个命令:pyenv global、pyenv local、pyenv shell。

pyenv global

此命令检查版本是否存在,存在则往 <pyenv 安装路径>/version 文件中写入设置的版本号。

pyenv local

此命令检查版本是否存在,存在则往 <当前路径>/.python-version 文件中写入设置的版本号。

pyenv shell

此命令检查版本是否存在,存在则往 PYENV_VERSION 环境变量中写入设置的版本号。

pyenv-version-name 查找版本流程

按以下顺序依次查找版本号:

  1. PYENV_VERSION 环境变量
  2. <当前路径>/.python-version 文件
  3. 依次遍历上级目录的 .python-version 文件
  4. <pyenv 安装路径>/version 文件

如果都没有找到,则使用系统安装的 Python 版本。

以上就是 pyenv 版本管理的基本原理了。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一文了解virtualenv、pyvenv、pyenv、pyenv virtualenv

    “生命苦短,我用 Python。”一句话说明了 Python 开发的便利性,这也是这么多开发者热衷 Python 的原因。

    Coder Sam
  • 当 MySQL 连接池遇上事务(一):神秘的幽灵锁

    MySQL连接池是一个很好的设计,通过将大量短连接转化为少量的长连接,从而提高整个系统的吞吐率。一般各个团队都会对连接池进行封装,只提供简洁的接口供上层使用。但...

    Coder Sam
  • 那些年,我们一起误解过的REST

    最近几年REST API越来越流行,特别是随着微服务的概念被广泛接受和应用,很多Web Service都使用了REST API。

    Coder Sam
  • python之pyenv安装 and i

    需要使用新版本Python的相关功能,但是又不想要影响到系统自带的Python,这个时候就需要实现Python的多版本共存。

    py3study
  • 使用 pyenv 可以在一个系统中安装多个python版本

    2016.01.06 21:02* 字数 82 阅读 24416评论 11喜欢 12

    拓荒者
  • Centos 7.4 多版本Python以及虚拟环境安装

    本人前端不太懂 Centos 上面的东西,这两天在搞阿里云的 Ecs 在上面安装 Python 环境,刚开始直接在官网下载了源码包编译安装了 Python3.7...

    拾贰
  • 在Ubuntu 18.04中安装pyen

    最近正在重头梳理Python的基础知识,为了更好地使用Python进行开发,防止发生版本混乱(不同的第三方库有可能因为Python版本不兼容而报错),所以需要使...

    py3study
  • pyenv 安装(管理多个版本pyth

        yum install -y gcc make patch gdbm-devel openssl-devel sqlite-devel zlib-de...

    py3study
  • Python项目包与包之间冲突是什么鬼?这次讲明白点!

    我们经常会遇到这类问题,往往没有注意环境隔离,导致Python项目包与包之间冲突。

    一墨编程学习
  • 为python版本抓狂,试下pyenv吧安装pyenv版本切换pyenv-virtualenv小结

    写python时,最烦的事莫过于版本切换。python3已经很成熟了,但很多生产项目依然用的是2.7版本,本地环境经常需要切换版本。此外,不同项目的依赖也不同,...

    章鱼喵

扫码关注云+社区

领取腾讯云代金券