Python多環境管理神器(pyenv)

前面我們已經介紹了,python中兩種最基礎的虛擬環境管理工具,venv和virtualenv,其中virtualenv可以和virtualenvwrapper配合使用。詳情請參考://www.cnblogs.com/doublexi/p/15783355.html

下面我們來介紹另一個python多環境管理神器pyenv

pyenv

pyenv 主要用來對 Python 解釋器進行管理,可以管理系統上的多個版本的 Python 解釋器。它的主要原理就是將新的解釋器路徑放在 PATH 環境變量的前面,這樣新的 python 程序就「覆蓋」了老的 python 程序,達到了切換解釋器的目的。

pyenv-virtualenv虛擬環境管理也是一樣,shims管理各個虛擬環境命令的路徑,然後再將shims路徑插入到系統環境變量最前面,達到切換虛擬環境的目的。

1、安裝pyenv:

pyenv不是自帶的,需要額外安裝。

方式一:

使用git來安裝:

git clone //github.com/pyenv/pyenv.git ~/.pyenv

配置環境變量:

sed -Ei -e '/^([^#]|$)/ {a \
export PYENV_ROOT="$HOME/.pyenv"
a \
export PATH="$PYENV_ROOT/bin:$PATH"
a \
' -e ':a' -e '$!{n;ba};}' ~/.bash_profile
echo 'eval "$(pyenv init --path)"' >> ~/.bash_profile

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
echo 'eval "$(pyenv init --path)"' >> ~/.profile

echo 'eval "$(pyenv init -)"' >> ~/.bashrc

請注意,以上的三條 echo 命令的最後一條長長的命令,請你保證它引號中的內容處於 ~/.bashrc 或者 ~/.zshrc 的最底部。

因為在 pyenv 初始化期間會操作 path 環境變量,導致不可預測的行為。

重啟當前shell,加載新的環境變量

exec $SHELL -l

測試是否安裝成功:

[root@ops-130 ~]# pyenv versions
* system (set by /root/.pyenv/version)

安裝過程如下:

clipboard

此時,表示pyenv安裝成功。

安裝方式二:

直接使用別人寫好的腳本一鍵安裝:

curl -L //github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 

安裝腳本有可能會提示你手動把幾行命令添加到shell的配置文件中。

將來要進行更新的話:

pyenv update 

要卸載pyenv的話更加簡單,直接刪除目錄即可:

rm -fr ~/.pyenv 

別忘了把.bashrc中的這幾行也一併刪掉:

export PATH="~/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

2、python環境管理

2.1、解釋器版本安裝與切換

使用pyenv安裝指定python版本

pyenv install 2.7.8 

安裝過程中,可能會顯示缺少一些包,補上就好了。

clipboard

先安裝依賴包:

yum install patch -y
pyenv install 2.7.8

安裝成功如下:

clipboard

安裝新版本後,需要rehash一下

pyenv rehash 

查看當前版本:

# 查看當前版本
pyenv version

# 查看 pyenv 已經託管了哪些 python 版本
pyenv versions

當前版本為系統使用版本:

clipboard

切換當前目錄的python版本為2.7.8

pyenv local 2.7.8

再次查看當前python版本,發現已經切換了。

clipboard

查看所有可安裝的軟件版本

[root@ops-130 ~]# pyenv install -l
Available versions:
  2.1.3
  ...
  2.7.15
  ...
  3.6.6
  3.7.0
  3.7-dev
  3.8-dev
  activepython-2.7.14
  activepython-3.5.4
  activepython-3.6.0
  anaconda-1.4.0
  ...  
  anaconda3-5.2.0
  ironpython-dev
  ironpython-2.7.4
  ironpython-2.7.5
  ironpython-2.7.6.3
  ironpython-2.7.7
  jython-dev
  jython-2.5.0
  jython-2.5-dev
  jython-2.5.1
  jython-2.5.2
  jython-2.5.3
  jython-2.5.4-rc1
  jython-2.7.0
  jython-2.7.1
  micropython-dev
  micropython-1.9.3
  micropython-1.9.4
  miniconda-latest
  miniconda-2.2.2
  ...
  miniconda3-4.3.30
  pypy-c-jit-latest
  pypy-c-nojit-latest
  pypy-dev
  pypy-stm-2.3
  pypy-stm-2.5.1
  pypy-1.5-src
  pypy-1.5
  ...
  pypy3.5-6.0.0
  pyston-0.5.1
  pyston-0.6.0
  pyston-0.6.1
  stackless-dev
  stackless-2.7-dev
  stackless-2.7.2
  ...
  stackless-3.5.4

2.2、virutalenv 使用 pyenv 安裝的 python 版本

// 通過 -p 參數指定 pyenv 安裝的 python 3.3.3 的 bin 目錄
# virtualenv -p /root/.pyenv/versions/3.3.3/bin/python3.3 py3.3

2.3、三種解釋器版本控制方法比較(global、shell、local)

pyenv控制版本的方式有三種,分別是:global、shell、local,下面分別來看看這三種方式:

首先是pyenv shell會話設置:(隻影響當前會話)

會話一:

[root@ops-130 ~]# pyenv versions
* system (set by /root/.pyenv/version)
  2.7.8
  3.3.3
# pyenv修改python版本  
[root@ops-130 ~]# pyenv shell 3.3.3
[root@ops-130 ~]# pyenv versions
  system
  2.7.8
* 3.3.3 (set by PYENV_VERSION environment variable)
[root@ops-130 ~]# python -V
Python 3.3.3
[root@ops-130 ~]#

可以看到,使用pyenv shell切換會話里的python版本後,

會話1的pyenv和python顯示版本均為3.3.3

會話二:

重新打開一個會話窗口,查看python版本

WARNING! The remote SSH server rejected X11 forwarding request.
Last login: Tue Jan  4 09:28:51 2022 from 192.168.90.197
[root@ops-130 ~]# cd /data/
[root@ops-130 data]# pyenv versions
* system (set by /root/.pyenv/version)
  2.7.8
  3.3.3
[root@ops-130 data]# python -V
Python 2.7.5
[root@ops-130 data]# 

可以看到新打開的會話是Python 2.7.5,並沒有受到影響,所以shell只會影響到當前的會話,一旦這個會話結束,則一切失效

pyenv local本地設置(隻影響當前目錄)

它會在當前目錄創建一個.python-version文件,裏面記錄著版本內容

新建目錄/data/test

[root@ops-130 test]# pyenv versions
* system (set by /root/.pyenv/version)
  2.7.8
  3.3.3
# pyenv local修改python版本  
[root@ops-130 test]# pyenv local 3.3.3
[root@ops-130 test]# pyenv versions
  system
  2.7.8
* 3.3.3 (set by /data/test/.python-version)
[root@ops-130 test]# python -V
Python 3.3.3
# 在當前目錄生成.python-version版本文件
[root@ops-130 test]# ls -a
.  ..  .python-version  test2
[root@ops-130 test]# cat .python-version 
3.3.3

創建一個子目錄test2

[root@ops-130 test]# mkdir test2
[root@ops-130 test]# cd test2
[root@ops-130 test2]# pyenv versions
  system
  2.7.8
* 3.3.3 (set by /data/test/.python-version)
[root@ops-130 test2]# python -V
Python 3.3.3

發現子目錄也隨之一起改變了

再回到父目錄查看:

父目錄不變。

所以pyenv local命令只會對當前的文件夾和其子目錄中的版本起作用 ,其他的目錄不起作用

[root@ops-130 test]# cd ..
[root@ops-130 data]# pyenv versions
* system (set by /root/.pyenv/version)
  2.7.8
  3.3.3
[root@ops-130 data]# python -V
Python 2.7.5

pyenv global 全局設置

如果使用此命令,可以看到所有受到pyenv控制的窗口都受到了影響, 所以儘可能不要用root用戶來安裝pyenv,否則會影響到之前的系統

原理是:

該命令執行後會在 $(pyenv root) 目錄(默認為 ~/.pyenv )中創建一個名為 version 的文件(如果該文件已存在,則修改該文件的內容),裏面記錄著系統全局的Python版本號。

# 全局設置,會覆蓋所有的目錄和窗口
[root@ops-130 ~]# pyenv global 2.7.8
[root@ops-130 ~]# pyenv versions
  system
* 2.7.8 (set by /root/.pyenv/version)
  3.3.3
# 會在~/.pyenv中創建version文件
[root@ops-130 ~]# ls /root/.pyenv/ 
bin    CHANGELOG.md  completions  Dockerfile  LICENSE   man      pyenv.d    shims  terminal_output.png  version
cache  COMMANDS.md   CONDUCT.md   libexec     Makefile  plugins  README.md  src    test                 versions
[root@ops-130 ~]# cat /root/.pyenv/version
2.7.8 

切換到其他目錄查看:

# opt也被改成了2.7.8
[root@ops-130 test]# cd /opt/
[root@ops-130 opt]# pyenv versions
  system
* 2.7.8 (set by /root/.pyenv/version)
  3.3.3

切換到之前local設置的目錄:local並沒有被global覆蓋

[root@ops-130 ~]# cd /data/test/
[root@ops-130 test]# pyenv versions
  system
  2.7.8
* 3.3.3 (set by /data/test/.python-version)

如果要取消pyenv的版本設置:

# 取消當前shell窗口的
pyenv shell --unset
# 取消當前目錄的
pyenv local --unset
# 取消全局設置
pyenv global system

優先級比較: shell > local > global

更多命令使用,參考官網://github.com/pyenv/pyenv/blob/master/COMMANDS.md#pyenv-local

3、虛擬環境管理 (pyenv-virtualenv)

3.1、安裝pyenv-virtualenv

pyenv要使用虛擬環境管理,必須安裝一個插件pyenv-virtualenv

git clone //github.com/pyenv/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
source ~/.bash_profile

查看是否安裝成功:

pyenv help virtualenv 

如下圖:

clipboard

3.2、虛擬環境創建與切換

使用pyenv創建虛擬環境(不需要指定目錄)

# 直接創建虛擬環境myproj3,它不需要指定目錄,不會在當前目錄生成myproj3目錄文件
pyenv virtualenv 3.3.3 myproj3

如下圖:會發現多出了兩個python的環境

clipboard

查看虛擬環境列表:

pyenv virtualenvs

如下圖:

clipboard

激活虛擬環境:

pyenv activate myproj3 

如下圖,環境已經激活,切換到了myproj3環境中,虛擬環境名已經出現在前綴上。

clipboard

退出虛擬環境

pyenv deactivate 

如下圖:

clipboard

刪除虛擬環境:

# 直接卸載該環境
pyenv uninstall myproj3

如下圖:

clipboard

3.3、虛擬環境隔離原理:(shims原理)

觀察PATH路徑,可以發現,pyenv的虛擬環境隔離是通過插入shims路徑到PATH頭部,實現的。

cat $PATH 

clipboard

shims路徑如下:裏面都是一些經常使用的命令引用路徑,pip、python等。

當切換虛擬環境時,pyenv就會將對應環境的命令拷貝,覆蓋掉shims路徑下的命令,並在PATH的頭部插入shims路徑,來實現python版本的切換。

(myproj3) [root@ops-130 ~]# ls /root/.pyenv/shims/
2to3      easy_install      idle     pip     pip3    pydoc3    python2           python2.7-gdb.py  python3.3         python3.3m-config  pyvenv      wheel
2to3-3.3  easy_install-2.7  idle3    pip2    pip3.3  pydoc3.3  python2.7         python2-config    python3.3-config  python3-config     pyvenv-3.3
activate  easy_install-3.3  idle3.3  pip2.7  pydoc   python    python2.7-config  python3           python3.3m        python-config      smtpd.py
(myproj3) [root@ops-130 ~]# which pip
/root/.pyenv/shims/pip

如下圖:

clipboard

3.4、關於虛擬環境pip沒有切換的問題

注意:(PS:使用pyenv-virtualenv創建虛擬環境的時候,經常因為下載pip不成功,導致pip包環境沒有切換過來。)

如下圖:這裡下載pip就沒有成功。

clipboard

此時,我們發現雖然成功創建了虛擬環境myproj,但是裏面的pip並沒有切換,如下:

# 雖然進入了虛擬環境,python環境切換過來了,但是pip環境還是舊的,沒有切換過來
(myproj3) [root@ops-130 ~]# pyenv versions
  system
  2.7.8
  3.3.3
  3.3.3/envs/myproj3
* myproj3 (set by PYENV_VERSION environment variable)
(myproj3) [root@ops-130 ~]# python -V
Python 3.3.3
# pip環境還是舊的
(myproj3) [root@ops-130 ~]# pip -V
pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7)
# 此時如果使用pip是無法安裝到對應的虛擬環境的

進入虛擬環境:我們手動重新安裝一下pip

curl //bootstrap.pypa.io/pip/3.3/get-pip.py | python

如下圖:

clipboard

再次驗證:發現此時pip已經切換過來了,可以使用pip安裝軟件包了。

(myproj3) [root@ops-130 ~]# which pip
/root/.pyenv/shims/pip
(myproj3) [root@ops-130 ~]# pip -V
pip 10.0.1 from /root/.pyenv/versions/myproj3/lib/python3.3/site-packages/pip (python 3.3)

如下圖:

clipboard

4、pyenv+anaconda

pyenv內部集成了anaconda的軟件包,可以在pyenv+anaconda環境。

# 查看軟件庫,有很多anaconda的版本,也有miniconda的
pyenv install --list

安裝anaconda3-2.5.0

# anaconda依賴bzip2,先安裝這個庫
yum install bzip2 -y
# pyenv安裝anaconda
pyenv install anaconda3-2.5.0

pyenv使用anaconda環境

# 方法一:直接切換anaconda環境

# 方法一:直接切換anaconda
[root@ops-130 test]# pyenv versions
  system
  2.7.8
* 3.3.3 (set by /data/test/.python-version)
  3.3.3/envs/myproj3
  anaconda3-2.5.0
  myproj3
[root@ops-130 test]# pyenv local anaconda3-2.5.0
# 發現裏面python版本也是anaconda自帶的版本3.5.1
[root@ops-130 test]# python -V
Python 3.5.1 :: Anaconda 2.5.0 (64-bit)
[root@ops-130 test]# which python
/root/.pyenv/shims/python

如下圖:

clipboard

方法二:創建使用anaconda的虛擬環境

# 創建虛擬環境的過程中,它會下載一些包,包括pip之類的。
[root@ops-130 ~]# pyenv virtualenv anaconda3-2.5.0  myproj4
查看當前託管版本:
[root@ops-130 ~]# pyenv versions
* system (set by /root/.pyenv/version)
  2.7.8
  3.3.3
  3.3.3/envs/myproj3
  anaconda3-2.5.0
  anaconda3-2.5.0/envs/myproj4
  myproj3
  myproj4

激活環境:

[root@ops-130 ~]# pyenv activate myproj4

如下圖:

clipboard

接下來,就可以使用conda來安裝管理庫了,

(myproj4) [root@ops-130 ~]# conda install py4j 

如下圖:

clipboard

退出虛擬環境:

pyenv deactivate 

5、優缺點分析:

1、pyenv極大程度的利用了環境變量工具,通過在環境變量前面插入新路徑來實現python解釋器版本管理和虛擬環境管理。

2、pyenv相比其他工具,更加側重在python 解釋器版本管理上, 比包管理更大一個層級, 使用pyenv我可以方便的下載指定版本的python解釋器, pypy, anaconda等, 可以隨時自由的在shell環境中本地、全局切換python解釋器

3、開發的時候不需要限定某個版本的虛擬環境, 只需要在部署的時候用pyenv local指定當前項目目錄使用某個版本就好了,很方便。

4、pyenv切換解釋器版本的時候, pip和ipython以及對應的包環境都是一起切換的。(PS:其他工具也是會一起切換的。)有些場景驗證多個版本的代碼更方便

(PS:使用pyenv-virtualenv創建虛擬環境的時候,經常因為下載pip不成功,導致pip包環境沒有切換過來。不過可以自己進入虛擬環境,再手動安裝pip解決這個問題。)

5、pyenv也可以創建好指定的虛擬環境, 但不需要指定具體目錄, 自由度更高, 使用也簡單

個人常用的做法是為每個項目創建不同的虛擬環境, 當進入該環境的時候就可以隨便浪而不用擔心影響到其它項目, 搭配Pycharm使用效果更佳.

注意:pyenv 不支持 Windows 系統。Windows 上有一個 pyenv 的替代品,是 pywin 。它用來在多個安裝的 Python 版本之間進行切換

Tags: