前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >pyenv 神器原理分析

pyenv 神器原理分析

原创
作者头像
Coder Sam
修改2020-03-03 22:53:30
3.5K0
修改2020-03-03 22:53:30
举报
文章被收录于专栏:Coder Sam的专栏

pyenv 是什么

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

pyenv 干什么

解决两种场景的问题……

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

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

image.png
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
image.png

使用 pyenv 之后

代码语言:txt
复制
# 安装各版本的 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 执行命令原理

有位伟人说过:

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

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

初始化 pyenv

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

代码语言:txt
复制
# vim ~/.bashrc
export PATH="/data/sammyshen/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

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

image.png
image.png

shims/垫片的简化基本原理

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

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

image.png
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
image.png

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

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

image.png
image.png

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

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

确定版本号

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

image.png
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 版本管理的基本原理了。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • pyenv 是什么
  • pyenv 干什么
    • 场景一:一台机器同时安装 Python 2.6、2.7、3.8
      • 场景二:一台机器同时使用同一个 Python 库的不同版本
      • 使用 pyenv 之后
      • pyenv 执行命令原理
        • 初始化 pyenv
          • shims/垫片的简化基本原理
            • 确定版本号
              • 确定与版本号对应的可执行文件
                • 执行命令
                • pyenv 版本管理原理
                  • pyenv global
                    • pyenv local
                      • pyenv shell
                        • pyenv-version-name 查找版本流程
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档