Python 版本管理工具選擇與 Pyenv 使用說明

曾左發表於2024-09-05

Python 版本管理工具的主要作用是幫助開發者在同一臺機器上管理多個 Python 版本和環境。這對於開發和部署不同專案非常有用,因為不同專案可能依賴不同的 Python 版本或者不同的包版本。具體來說,Python 版本管理工具應有以下功能:

(1)避免依賴衝突,不同的專案可能依賴不同版本的庫,使用版本管理工具可以建立獨立的虛擬環境,避免依賴衝突。

(2)簡化開發流程,開發者可以輕鬆地在不同的 Python 版本之間切換,而不需要重新安裝或配置 Python。

(3)便於部署,減少衝突。在開發環境中使用與生產環境相同的 Python 版本和依賴,可以減少部署時出現的問題。

(4)共享環境配置,提高開發環境一致性。可以將環境配置檔案(如 requirements.txtpyproject.toml)共享給團隊成員,確保大家使用相同的開發環境。

一、工具選擇

常見的管理工具有 Pyenv 和 Conda。Pyenv 是當前最流行的 Python 版本管理工具,支援多種 Python 版本,如 CPython、Anaconda、PyPy 等,功能全面且簡單易用。Conda 最初由 Anaconda, Inc. 開發,主要用於 Python 和 R 程式語言的軟體包(含 Python)及環境管理,特別適合跨平臺、多語言專案,Python 版本管理只是其一小部分功能,若僅用於管理 Python 版本,Conda 有些大材小用,且系統較複雜、學習成本略高。相比之下,Pyenv 是常規專案 Python 版本管理的最優選擇。

以下詳細介紹 Pyenv 的使用方法。

二、Pyenv 安裝

建議: 先解除安裝系統內建的 Python,否則可能導致 pyenv 設定不生效。

1. Windows

pyenv 本身是為 Unix 系統設計的。你可以使用 pyenv-win 這個專案,它是 pyenv 的 Windows 版本。

你需要在 PowerShell 中執行以下命令安裝 pyenv-win:

Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"

重新開啟 PowerShell,執行 pyenv --version 檢查安裝是否成功。

2. Linux

你可以使用以下命令來安裝 pyenv

curl https://pyenv.run | bash

之後再將 pyenv 配置到環境變數中並使之生效,執行如下命令:

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

上述配置僅能使 pyenv 在 bash 環境生效,更多 shell 環境配置請參考:Set up your shell environment for Pyenv。配置的本質在於將$PYENV_ROOT 下的 shims 和 bin 目錄配置到 PATH 變數中,且 shims 需配置在前。配置後的 PATH 如下:

[root@2e7669577b11 /]# echo $PATH
/root/.pyenv/shims:/root/.pyenv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

三、Pyenv 基本用法

## 檢視幫助文件
pyenv

## 檢視某個命令幫助文件
pyenv install --help

## 檢視版本
pyenv version

## 檢查 Python 是否正常執行
python -c "import sys; print(sys.executable)"

## 檢視已安裝的 Python 版本
pyenv versions

## 檢視當前使用的 Python 版本
pyenv version

## 檢視所有可用的 Python 版
pyenv install --list 

## 安裝指定版本
pyenv install 3.9.1

## 驗證
python --version

## 解除安裝指定版本
pyenv uninstall 3.9.1

## 全域性指定 Python 版本(影響所有專案)
pyenv global 3.9.1 

## 區域性指定 Python 版本(僅影響當前專案目錄),指定後在當前專案目錄內建立 .python-version 檔案,儲存版本資訊
## 優先順序高於 global
pyenv local 3.9.1

## 會話級指定 Python 版本(影響所有專案)
pyenv shell 3.9.1 

## 檢視 python 的安裝目錄
pyenv which python

## 重新生成 pyenv 的 shims 目錄中的可執行檔案
pyenv rehash 

Python 安裝常見問題,可參考:Python common build problems

四、Pyenv 核心原理 -Shims

pyenv 透過 Shims 實現了對不同 Python 版本的透明管理和切換。

1. 工作原理

上述環境配置中,在 PATH 環境變數最前面插入一個 shims 目錄,$(pyenv root)/shims:$(pyenv root)/bin:/usr/local/bin:/usr/bin:/bin。透過一個稱為 rehashing 的過程,pyenv 在該目錄中維護墊片,以匹配每個已安裝的 Python 版本中的每個 Python 命令,如: python、pip 等。

Shims 是輕量級可執行檔案,它只是將你的命令傳遞給 pyenv。因此,在安裝了 pyenv 的情況下,當你執行 pip 時,你的作業系統將執行以下操作:

(1)搜尋 PATH 環境變數,尋找 pip 可執行檔案

(2)在 $(pyenv root)/shims 中找到 pip

(3)執行名為 pip 的 shim,它將命令傳遞給 pyenv

2. 作用

(1)透過使用 Shims,pyenv 可以實現對不同專案使用不同 Python 版本的靈活管理,而不需要手動修改環境變數或路徑。

(2)你可以方便地在全域性、目錄級別甚至是 shell 會話級別設定或切換 Python 版本,極大地方便了開發和測試工作。

3. 示例

(1)假設你在專案 A 中使用 Python 3.8,而在專案 B 中使用 Python 3.9。透過 pyenv 和 Shims,你可以在專案目錄中分別設定 Python 版本:

# 在專案 A 目錄中
pyenv local 3.8.10

# 在專案 B 目錄中
pyenv local 3.9.5

(2)當你在專案 A 目錄中執行 python 命令時,Shims 會確保呼叫的是 Python 3.8.10,而在專案 B 目錄中則會呼叫 Python 3.9.5。

透過這種方式,Shims 實現了對不同 Python 版本的透明管理和切換。

五、Pyenv 初始化操作原始碼解讀

1. pyenv init -

用於初始化 pyenv,使其在當前 shell 會話中工作。執行後,執行如下命令(相關說明附在註釋中):

# 1.PATH 變數處理
## 該指令碼將當前的 PATH 變數拆分為一個陣列 paths,並賦予
## 透過遍歷 paths 陣列,檢查每個路徑是否為 '/root/.pyenv/shims',如果是,則將其移除
PATH="$(bash --norc -ec 'IFS=:; paths=($PATH); 
for i in ${!paths[@]}; do 
if [[ ${paths[i]} == "''/root/.pyenv/shims''" ]]; then unset '\''paths[i]'\''; 
fi; done; 
echo "${paths[*]}"')" # 

# 2. 更新 PATH 變數
## 將 '/root/.pyenv/shims' 新增到 PATH 變數的最前面
export PATH="/root/.pyenv/shims:${PATH}"
## 設定 PYENV_SHELL 環境變數為 bash,sh 環境下,輸出的是 shell
export PYENV_SHELL=bash
## sh 環境下,無該行程式碼,bash 環境下執行改行的作用是:source 命令載入 pyenv 的自動補全指令碼
source '/root/.pyenv/libexec/../completions/pyenv.bash' 
## 透過 command 命令執行 pyenv rehash(主要作用是重新生成 pyenv 的 shims 目錄中的可執行檔案),並將錯誤輸出重定向到 /dev/null
command pyenv rehash 2>/dev/null

# 3. 定義一個 pyenv 函式,該函式根據不同的子命令執行不同的操作
## 如果子命令是 activate、deactivate、rehash 或 shell,則透過 eval 執行 pyenv "sh-$command"
## 對於其他子命令,直接呼叫 command pyenv "$command" "$@"
pyenv() {
  local command
  command="${1:-}"
  if [ "$#" -gt 0 ]; then
    shift
  fi

  case "$command" in
  activate|deactivate|rehash|shell)
    eval "$(pyenv "sh-$command" "$@")"
    ;;
  *)
    command pyenv "$command" "$@"
    ;;
  esac
}

2. pyenv init --path

用於設定 PYENV_ROOT 環境變數,使得 pyenv 可以找到安裝的 Python 版本。pyenv init - 包含 pyenv init --path 操作。

sh 或 bash 環境執行後,執行如下命令(相關說明附在註釋中):

## 該指令碼將當前的 PATH 變數拆分為一個陣列 paths,並賦予
## 透過遍歷 paths 陣列,檢查每個路徑是否為 '/root/.pyenv/shims',如果是,則將其移除
PATH="$(bash --norc -ec 'IFS=:; paths=($PATH); 
for i in ${!paths[@]}; do 
if [[ ${paths[i]} == "''/root/.pyenv/shims''" ]]; then unset '\''paths[i]'\''; 
fi; done; 
echo "${paths[*]}"')"
## 將 '/root/.pyenv/shims' 新增到 PATH 變數的最前面
export PATH="/root/.pyenv/shims:${PATH}"
## 透過 command 命令執行 pyenv rehash,並將錯誤輸出重定向到 /dev/null
command pyenv rehash 2>/dev/null

六、參考文章

pyenv

Python common build problems

相關文章