by David Besh from Pexelsby David Besh from Pexels

合輯:Python 開發環境設定:zsh、zinit、pyenv、Poetry、Docker

告別 Anaconda:在 macOS 上使用 pyenv 建立 Python 開發環境〉介紹了 pyenv 在 macOS 上的安裝與使用。

事實上,它更常被使用的場景應該是 Linux,畢竟無論是 Windows 或 macOS 都有功能相仿但更無腦且容易上手的選擇——Anaconda。

Anaconda 具有 GUI 的優勢,確實很方便,結合 conda 的虛擬環境管理,對尚不熟悉 virtualenv 的 Python 初學者而言較為友好,我自己也用了好長一段時間。

Anaconda NavigatorAnaconda Navigator

所以,不得不承認,Anaconda 雖肥,但它確實是入門者的首選!


pyenv on Linux

但只要是開發者,無論是自己租的 VPS 還是公司用來測試的環境,相信十之八九都是安裝了 Ubuntu 或其他發行版的 Linux 執行個體。

因此,學會在 Ubuntu 上使用 pyenv 無疑更加值得,甚至是必要!因為想在 Linux 上安裝不同版本的 Python 並同時做好虛擬環境管理,著實不是一件輕鬆的事——除非你有了 pyenv。這也是為何它如此受歡迎的原因(GitHub 26.5k stars),可謂用過的都說好!

二話不說,就來試試吧!和 macOS 的差別不大,只是要額外安裝一些 dependency package,以及 Linux 上沒有brew install這個選項而已。

為了確保本篇內容的正確與可行,在寫這篇文章的同時,我也在自己的 GCP 新建一個 f1-micro 等級的 VM(virtual machine)進行 pyenv 安裝,選擇的作業系統版本為 Ubuntu 20.04.1。

安裝 pyenv

安裝前請再看一下 pyenv 的 GitHub 首頁,大部分的流程都已經寫在這裡,也可參考我之前的文章

基本上照本篇一步一步執行應該都可以成功。

先安裝 dependency package

第一步,也是主要的差異,就是要先安裝相關依賴套件:

1
sudo apt-get update; sudo apt-get install -y --no-install-recommends make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev

注意這些套件名稱可能會隨著不同的 Linux 發行版而有差別,CentOS 的用戶需要另外 google 確認名稱是否相同。

從 GitHub 安裝 pyenv

因為不是 macOS 所以沒有 Homebrew,在 Liunx 上只能以git clone安裝:

1
git clone https://github.com/pyenv/pyenv.git ~/.pyenv

設定 pyenv

主要看你用哪個 shell,不同的 shell 設定也不同,而 Ubuntu 自帶的是 bash,故先以 bash 為例。


2023/04/07重要更新:pyenv 2.3.0 以後,已經大幅簡化了設定操作,本段內容在新版仍可適用,但建議直接升級最新版 pyenv 並直接改用以下設定

1
2
3
export PYENV_ROOT="$HOME/.pyenv"
command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

官方的 shell 指令版本(for zsh):

1
2
3
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

這三行設定,無論 bash 或 zsh 皆同;.profile.zprofile 如果需要,增加的內容也完全一樣!真的簡化了很多,不用再去判斷是哪種 shell 了。


bash:設定.bashrc.profile

這部分很重要且容易出錯。

最簡單且穩健的方式就是直接複製並執行下面這兩段 script:

1
2
3
4
5
6
7
8
9
10
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
1
echo 'if command -v pyenv >/dev/null; then eval "$(pyenv init -)"; fi' >> ~/.bashrc

完成!


zsh:設定 zsh 的.zprofile.zshrc

推薦使用 zsh,取得更佳的命令列體驗與工作效率,安裝教學可參考:Ubuntu 安裝使用 zsh + 輕量級套件管理器 zinit

  • .zprofile新增,使用echo指令
1
2
3
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zprofile
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zprofile
echo 'eval "$(pyenv init --path)"' >> ~/.zprofile
  • .zshrc新增,一樣使用echo指令
1
echo 'eval "$(pyenv init -)"' >> ~/.zshrc

這樣看起來,zsh 的設定是不是簡單很多呢?😎


安裝與設定 pyenv-virtualenv

非必要步驟,可以選擇自己喜好的虛擬環境管理工具,但既然都選用了 pyenv,當然還是推薦一併安裝 pyenv-virtualenv。

從 GitHub 安裝 pyenv-virtualenv

一樣先參考官方文件

1
git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv

注意,請務必確認已經安裝 pyenv 並正確設定好.bashrc/.zshrc後,再來執行此步驟,以免發生路徑錯誤。

bash:設定.bashrc

官方文件有說這一步是 optional,如果無法正常運行再設定即可。

一樣,複製貼上執行:

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

zsh:設定.zshrc

1
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshrc

最後,別忘了

重登或source ~/.bashrcsource ~/.zshrc或直接exec "$SHELL"


pyenv 安裝 Python、使用 virtualenv

以建立 Python 3.8 的虛擬環境(virtualenv)為例:

  1. 安裝 Python 3.8.12
  2. 將 3.8.12 設為系統預設的 Python 版本
  3. 非必要:切換當前 shell 的 Python 版本為 3.9.5
  4. 以 3.8.12 建立虛擬環境
  5. 啟動虛擬環境
  6. 退出虛擬環境
  7. 移除虛擬環境

一、安裝 Python 3.8.12

1
pyenv install 3.8.12

執行後的訊息為:

1
2
3
Downloading Python-3.8.12.tar.xz...
-> https://www.python.org/ftp/python/3.8.12/Python-3.8.12.tar.xz
Installing Python-3.8.12...

特別提醒:如果電腦硬體規格不佳,比如本篇中的 f1-micro,則安裝會非常耗時,會停在上述訊息很長一段時間,可能超過 20 分鐘,並不是當機了。

具體的原因如本討論串回覆所述:

Please try with larger instance types during pyenv install. Because the pyenv install will build CPython from source, it consumes bunch of memory and CPU cycles.

這段論述頗為真實,同一 Python 版本我用本機安裝時速度快很多。而 f1-micro 大概耗費了 25 分鐘,非常久,期間 CPU 都是 100% 負載運作。

硬體性能太弱,CPU 100% 負載運作硬體性能太弱,CPU 100% 負載運作

你可以安裝多個不同版本的 Python,並使用pyenv globalpyenv local指令進行版本切換,這是 pyenv 的最大賣點,但操作上沒什麼困難,就不特別細講。

要查看有哪些 Python 版本可供安裝,可使用指令pyenv install --listpyenv install -l查詢:

1
2
3
4
5
6
7
8
❯ pyenv install -l
Available versions:
2.1.3
2.2.3
2.3.7
...
stackless-3.5.4
stackless-3.7.5

要查看目前已經安裝哪些版本的 Python,則使用指令pyenv versions

1
2
3
4
5
6
7
8
9
❯ pyenv versions
* system
3.7.11
3.7.11/envs/project1-env
3.7.11/envs/project2-env
3.8.12
3.9.5
project1-env
project2-env

可以看出,這個指令會一併顯示基於該 Python 版本建立的虛擬環境

二、將 3.8.12 設為系統預設的 Python 版本

1
pyenv global 3.8.12

注意:這裡所謂的「global(全域)」只對「當前使用者」的 shell 有效,因為我們在前面設定過.bashrc.zshrc等檔案。

此時再使用pyenv versions確認:

1
2
3
4
5
6
7
8
9
❯ pyenv versions
system
3.7.11
3.7.11/envs/project1-env
3.7.11/envs/project2-env
* 3.8.12 (set by /home/kyo/.pyenv/version)
3.9.5
project1-env
project2-env

*的提示可知,當前 Python 版本已切換為 3.8.12。

三、非必要:切換當前 shell 的 Python 版本為 3.9.5

這個需求通常是 global 版本不是我們想要的,但又不想改變 global 版本,也不想設 local,只想暫時切換當前 shell 的 Python 版本。

比如我某個專案的 Poetry 虛擬環境,需要使用 Python 3.9.5 來建立,而不是 global 的 3.8.12,則可以使用以下指令:

1
2
pyenv shell 3.9.5  # 已安裝 3.9.5
poetry env use 3.9.5 # 建立 Poetry 虛擬環境

四、以 3.8.12 建立虛擬環境

在此命名虛擬環境為:luffy。

1
pyenv virtualenv 3.8.12 luffy
  • 需要指定 pyenv 已安裝的 Python 版本,此處指定3.8.12
  • 不指定版本時,會以當前 pyenv 正在使用的版本建立虛擬環境。

確認虛擬環境已經建立:

1
2
3
4
5
6
❯ pyenv versions
...
* 3.8.12 (set by /home/kyo/.pyenv/version)
3.8.12/envs/luffy
...
luffy

五、啟動虛擬環境 luffy

1
pyenv activate luffy

啟動後的效果:

1
2
3
4
5
6
❯ pyenv versions
...
3.8.12
3.8.12/envs/luffy
...
* luffy (set by PYENV_VERSION environment variable)

此時就可以pip安裝你需要的套件了。

六、退出虛擬環境

1
pyenv deactivate luffy

七、移除虛擬環境

1
pyenv uninstall luffy