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)
安裝過程如下:
此時,表示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
安裝過程中,可能會顯示缺少一些包,補上就好了。
先安裝依賴包:
yum install patch -y pyenv install 2.7.8
安裝成功如下:
安裝新版本後,需要rehash一下
pyenv rehash
查看當前版本:
# 查看當前版本 pyenv version # 查看 pyenv 已經託管了哪些 python 版本 pyenv versions
當前版本為系統使用版本:
切換當前目錄的python版本為2.7.8
pyenv local 2.7.8
再次查看當前python版本,發現已經切換了。
查看所有可安裝的軟件版本
[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
如下圖:
3.2、虛擬環境創建與切換
使用pyenv創建虛擬環境(不需要指定目錄)
# 直接創建虛擬環境myproj3,它不需要指定目錄,不會在當前目錄生成myproj3目錄文件 pyenv virtualenv 3.3.3 myproj3
如下圖:會發現多出了兩個python的環境
查看虛擬環境列表:
pyenv virtualenvs
如下圖:
激活虛擬環境:
pyenv activate myproj3
如下圖,環境已經激活,切換到了myproj3環境中,虛擬環境名已經出現在前綴上。
退出虛擬環境
pyenv deactivate
如下圖:
刪除虛擬環境:
# 直接卸載該環境 pyenv uninstall myproj3
如下圖:
3.3、虛擬環境隔離原理:(shims原理)
觀察PATH路徑,可以發現,pyenv的虛擬環境隔離是通過插入shims路徑到PATH頭部,實現的。
cat $PATH
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
如下圖:
3.4、關於虛擬環境pip沒有切換的問題
注意:(PS:使用pyenv-virtualenv創建虛擬環境的時候,經常因為下載pip不成功,導致pip包環境沒有切換過來。)
如下圖:這裡下載pip就沒有成功。
此時,我們發現雖然成功創建了虛擬環境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
如下圖:
再次驗證:發現此時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)
如下圖:
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
如下圖:
方法二:創建使用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
如下圖:
接下來,就可以使用conda來安裝管理庫了,
(myproj4) [root@ops-130 ~]# conda install py4j
如下圖:
退出虛擬環境:
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 版本之間進行切換