by Koma Zhang on Behanceby Koma Zhang on Behance

2022/01/19更新:重寫 Python 與專案兩種不同層級虛擬環境管理介紹;設定部分明確區分 zsh 與 bash 使用者。

Ubuntu 版:Ubuntu 安裝使用 pyenv + pyenv-virtualenv

「人生苦短,我用 Python」闡述了 Python 的易用與簡潔,但如果深入到 Python 的套件管理與版本隔離,則是一件十分複雜的事,有興趣的人可以參考下列內容:

本篇重點

這次並沒有要細論上述內容,寫作動機只是最近想把 Anaconda 這個初學 Python 時都一定知曉的工具移除掉,我現在的 Python 虛擬環境都是用 Anaconda 附帶的 conda 建立與管理居多,而最常見的替代方案,就是 pyenv。

本篇僅記錄一下設定上的重點,詳細用法請參考 pyenv 官方 GitHub

為何要從 conda 轉向 pyenv?

倒沒什麼重大的原因,真要說的話,就是為了「簡潔」而已。

所有用 conda 建立的虛擬環境都同時可以用 pip 或 conda 來安裝第三方套件,這樣容許混雜的模式讓我略感煩躁。

其次是 conda 的 base env 真的很肥大,畢竟幫你灌好了一堆資料科學套件,雖然方便,但這也是最常被垢病的部分,可謂雙面刃。而且我的定位是後端工程師啊!

不同層級的虛擬環境管理:Python vs 專案

值得一提的是,「不同 Python 版本間的虛擬環境管理」「不同專案間的虛擬環境管理」基本上是兩件事,只不過 Anaconda 透過 conda 同時都能做到而已。conda 在建立虛擬環境的同時會要求你選擇 Python 版本,所以不同 conda env 間的 Python 版本可以不同。

而 pyenv 則是比較偏向 Python 版本管理,雖然你要直接當套件管理的虛擬環境來用也未嘗不可,但還是推薦使用 virtualenv 較為合理。

Python 層級的虛擬環境管理方案

可以管理複數版本的 Python,方便不同專案需使用不同 Python 的情境,說實在的也是很常見。

  • conda:即將捨棄。
  • pyenv:本文重點。
  • Docker:以容器建立開發環境也是一個趨勢(如下圖),比如 VS Code 的 DevContainer,這部分在此先不討論。

Python Developers Survey 2020 Results by JetBrainsPython Developers Survey 2020 Results by JetBrains

單一專案虛擬環境管理方案

這裡管理範圍著重於專案所安裝的套件與套件版本

  • Python 內建的 venv:通常直接放在特定專案的根目錄底下,因為沒有更高層的封裝讓你可以輕鬆跨專案打開,路徑要自己找,較適合單一專案使用。
  • virtaulenv:最常見的虛擬環境管理方案。
  • pyenv-virtualenv:pyenv 的 virtualenv 高階封裝版本。
  • pipenv、poetry 等套件管理工具:前者小荒廢,後者還很新,主要的亮點都是在處理套件之間的版本依賴問題,現階段暫時不考慮。

以上都只是套件管理,如果要連同 Python 的版本一起管理(這顯然是個硬需求),還是需要 pyenv。


安裝 pyenv 與 pyenv-virtualenv

1
2
3
brew update
brew install pyenv
brew install pyenv-virtualenv

裝完之後要設定.bashrc.zshrc,還有.bash_profile.zprofile,端視你的 shell 是哪個。目前新版本的 macOS 預設 shell 為 zsh

相關文章:Ubuntu 安裝使用 zsh + 輕量套件管理器 zinit

zsh 使用者

設定的內容主要是提供正確的 Python PATH,這部分很關鍵。具體要新增什麼內容,各教學或官方的版本沒有完全一致,不過大同小異,在此提供我實際新增的部分,注意以下皆是以 Homebrew 安裝的 pyenv 為例:

  • .zprofile新增

你可能跟我一樣一開始也沒有這個檔,直接用官方給的指令新增就好:

1
echo 'eval "$(pyenv init --path)"' >> ~/.zprofile
  • .zshrc新增
1
2
3
if command -v pyenv 1>/dev/null 2>&1; then
eval "$(pyenv init -)"
fi

特別說明,官方教學只說需要新增中間的eval "$(pyenv init -)",但我光這樣設定,會無法切換全域 Python 版本,看了這篇之後改成上述的版本。

設定好後記得要分別 source 一下。

bash 使用者

如果是 bash 用戶,建議設定上一律直接使用官方提供的這兩段 script 就好了,最簡單無腦且不會出錯,記得兩個部分都要執行喔!

第一部分

1
2
3
4
5
6
7
8
9
10
11
echo -e 'if shopt -q login_shell; then' \
'\n export PYENV_ROOT="$HOME/.pyenv"' \
'\n export PATH="$PYENV_ROOT/bin:$PATH"' \
'\n eval "$(pyenv init --path)"' \
'\nfi' >> ~/.bashrc
# 注意檔名
echo -e 'if [ -z "$BASH_VERSION" ]; then'\
'\n export PYENV_ROOT="$HOME/.pyenv"'\
'\n export PATH="$PYENV_ROOT/bin:$PATH"'\
'\n eval "$(pyenv init --path)"'\
'\nfi' >>~/.profile

不過要稍為注意一下.profile名稱,在 macOS 上通常為.bash_profile

1
2
3
4
5
echo -e 'if [ -z "$BASH_VERSION" ]; then'\
'\n export PYENV_ROOT="$HOME/.pyenv"'\
'\n export PATH="$PYENV_ROOT/bin:$PATH"'\
'\n eval "$(pyenv init --path)"'\
'\nfi' >>~/.bash_profile

第二部分

1
echo 'if command -v pyenv >/dev/null; then eval "$(pyenv init -)"; fi' >> ~/.bashrc

上述設定完後記得要source或重啟 shell。


簡單設定與使用

以我的例子:

  1. 建立一個全域的 Python 3.7.11 環境。
  2. 建立一個使用 Python 3.7.11 的虛擬環境。
1
2
3
4
5
6
#1
pyenv install 3.7.11
pyenv global 3.7.11 # 將全域的 Python 版本設為 3.7.11

#2
pyenv virtualenv 3.7.11 my_venv<自行命名>

如果已經在 pyenv 的 3.7.11 環境下,則上述 #2 的3.7.11可以省略,只要pyenv virtualenv my_venv即可建立虛擬環境。

啟用與停止虛擬環境

1
2
pyenv activate my_venv
pyenv deactivate my_venv

移除虛擬環境

1
pyenv uninstall my_venv

查看目前所有虛擬環境

1
pyenv virtualenvs

你會看到每一個虛擬環境都有兩個項目,這是正常的:

There are two entries for each virtualenv, and the shorter one is just a symlink.

像下面這樣:

1
2
3.7.11/envs/my_venv (created from /Users/kyo/.pyenv/versions/3.7.11)
* my_venv (created from /Users/kyo/.pyenv/versions/3.7.11)

小結

使用 pyenv 建立不同 Python 版本並管理相對應的虛擬環境實在非常方便!

附帶一提,雖然不一定要安裝 pyenv-virtualenv 而可以直接pip virtualenv即可,但後者的使用方式類似內建的 venv,比較沒有那麼彈性。

此外,pyenv-virtualenv 在 3.3 版本以上的 Python,實際上就是調用內建的 venv 來建立虛擬環境,否則就是調用 virtualenv,總之就是多一層封裝讓使用變得更方便而已。

參考