专栏首页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
  • 为python版本抓狂,试下pyenv吧安装pyenv版本切换pyenv-virtualenv小结

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

    章鱼喵
  • python版本管理工具:pyenv

    这几天在学习python,因为我学的是python3的语法,但是我ubuntu默认安装的是python2,我sqlmap需要的环境也是python2的,但是我需...

    kevinfaith
  • 你应该学会的Python多版本管理工具P

    可以看到,是从pyenv也是官方网站下载编译安装的。warning提示的是害怕通过pyenv安装的python会使用提示的文件中的配置,从而影响新安装的py...

    py3study
  • Python多版本管理器-pyenv 介绍及部署记录

    在日常运维中, 经常遇到这样的情况: 系统自带的Python是2.x,而业务部署需要Python 3.x 环境, 此时需要在系统中安装多个Python版本,但又...

    洗尽了浮华
  • 【Python】03、python多版本

     CentOS6系统会自带一个较低版本的python,一般不使用系统自带的python版本,因为系统很多组件依赖于python比如yum,如果我们随意升级或者...

    py3study
  • Auto Remove Torrents:自动删种程序部署

    autoremove-torrents是一个用Python3写的自动删除种子的程序,目前支持qBittorrent/Transmission/μTorrent客...

    砸漏
  • Python多环境扩展管理

    众所周知,Python发展至今,版本众多,在使用过程中经常遇到第三方库依赖的Python版本和系统Python版本不一致的情况。同时又因系统底层需调用当前版本P...

    子润先生
  • 你所会用到的Python学习环境及工具

    备注:所以使用的操作系统环境为CentOS 6.2 编译安装python 2.7及ipython 1、下载所需要的程序包 ipython-1.2.1.tar.g...

    小小科
  • pyenv快速入门

    版权声明:本文为博主原创文章,转载请注明出处。 ...

    乐百川
  • Python版本切换与虚拟环境管理

    Python2和Python3之间存在较大的差异,并且由于各种原因导致Python2和Python3长期共存。我们在使用的时候,可能会遇到不同的Python版本...

    py3study
  • Python关键点笔记之使用 pyenv 管理多个 Python 版本依赖环境

    从接触Python以来,一直都是采用virtualenv和virtualenvwrapper来管理不同项目的依赖环境,通过workon、mkvirtualenv...

    Jetpropelledsnake21
  • 基于pyenv和virtualenv搭建python多版本虚拟环境

    pyenv简介 由于Python的依赖是基于site的,这对于生产环境来说,是一种简单而正确的方式,然而,对于我们的开发环境,基于这样的管理方式,带来了可怕的第...

    Python中文社区
  • jupyter、pyenv、virtualenv、virtualenvwrapper简要区别

    在创建一个新的python版本时,完全拷贝一个现成的python环境。新的python版本,可作为global

    晓歌
  • Linux下python环境的搭建

    如果安装提示 curl: (35) SSL connect error ,是nss版本低的问题,更新它就可以了。需要配置一个有较新包的yum源。配置内容如下:

    py3study
  • Python版本管理利器--pyenv

    设置局部python版本,将Python版本写进当前目录下的.python-version 文件,这个版本号会覆盖全局的版本号,可以被PYENV_VERSION...

    用户2936342
  • crontab 定时执行 pyenv 下的 python 脚本不成功

    通过 pyenv 管理不同版本的 Python,但使用 crontab 定时执行脚本时,脚本未成功运行。

    文渊同学
  • 我就感觉到快 —— zsh 和 oh my zsh 冷启动速度优化

    不论是在 WSL、Linux 还是 macOS 上,强大的 zsh 一直是我的不二法宝,而 oh my zsh 自然成了最趁手的瑞士军刀,我自己还编写了数个 o...

    米开朗基杨
  • 002-Python编程环境的各种姿势

    pip是Python的软件包管理工具,可以用来安装、升级与卸载Python的软件包。从Python3.4版本开始,系统已经自带pip工具了。

    py3study

扫码关注云+社区

领取腾讯云代金券