AI & Data Dreamers練功房
寶箱片場規則
前傳・開工前環境安裝

Python 環境:pyenv+pipenv

← 回資料館・在 GitHub 看原始檔(de-course)・裝到一半卡住?左下角送件鴿或 Discord #觀眾服務台 喊一聲

9. Part 3:Python 環境管理概念

📣 「前半段我們把協作工具搞定了。接下來進入 Python 工程的核心——環境管理。這是新手和專業工程師最明顯的分水嶺。」

9-1. 一個你遲早會遇到的真實情境

📣 「假設你接了兩個案子。」

專案 A(一個維護兩年的舊系統)
  需要 Python 3.8
  需要 pandas 1.5(新版 pandas 改了 API,升上去就壞)

專案 B(你這學期的新專案)
  需要 Python 3.11
  需要 pandas 2.x(要用新功能)

如果你把所有東西都裝在「同一個 Python」裡,會發生什麼?

你做的事 結果
為了 B 升級 Python 到 3.11 專案 A 的某些舊語法 / 舊套件可能不相容
為了 B 升級 pandas 到 2.x 專案 A 跑到一半噴 AttributeError,因為 API 變了
想退回去救 A B 又壞了——你陷入「救一個壞一個」的死循環

📣 「這就是『依賴地獄』(dependency hell)。沒有環境管理,你的電腦只有一套 Python、一套套件,所有專案被迫共用,遲早互相打架。」

9-2. 環境管理在解什麼問題

核心只有三件事:

問題 沒有環境管理 有環境管理
多版本 Python 全機只能裝一個 pyenv 隨資料夾切換
套件版本衝突 A 升級壞了 B 每個專案一個獨立虛擬環境,互不干擾
別人能重現嗎 「在我電腦可以跑啊」 lockfile 鎖死每個套件版本,照著裝就一模一樣

💡 關鍵詞:隔離(isolation)。環境管理的本質就是「把每個專案關進自己的小房間」,房間裡的 Python 版本、套件版本,都不影響別的房間。

9-3. 環境管理工具全覽

Python 生態的工具很多,新手常被名字搞混。先建立全貌:

工具 管 Python 版本 管套件 管虛擬環境 一句話定位
venv ✗ ✗ ✓ Python 內建,只建虛擬環境,最陽春
pyenv ✓ ✗ ✗ 專門切換多個 Python 版本
pipenv ✗ ✓ ✓ 套件 + 虛擬環境,自帶 lockfile(本課主力)
poetry ✗ ✓ ✓ 跟 pipenv 類似,偏「發布套件」的人愛用
conda ✓ ✓ ✓ 資料科學圈愛用,能裝非 Python 的東西(CUDA 等),但較重
uv ✓ ✓ ✓ 用 Rust 寫的新星,超快,一個工具全包(現代補充)

📣 「不用全部都學。官方課綱選的組合是 pyenv(管版本)+ pipenv(管套件)——業界最常見、面試最常被問的組合。最後再補介紹 uv,讓你知道未來新專案可以考慮的現代選項。」

今天聚焦的分工:

工具 管什麼 比喻
pyenv Python 版本(3.8 / 3.11 …) 選你要用哪一台「Python 主機」
pipenv 套件 + 虛擬環境 每個專案專屬的「套件工具箱」

9-4. pyenv 怎麼運作(shims 機制)

pyenv 的魔法在於它攔截你打的 python 指令,再決定真正要跑哪個版本。這個攔截層叫 shims(墊片)。

你在終端機打:python
        │
        ▼
   pyenv 的 shim 先接到(PATH 最前面是 pyenv)
        │
   shim 問:「現在這個資料夾指定了哪個版本?」
        │
        ├── 找到 .python-version → 用裡面寫的版本(例如 3.11.9)
        ├── 沒找到 → 往上一層資料夾找
        └── 都沒有 → 用 pyenv global 設的預設版本
        │
        ▼
   真正執行對應版本的 python

📸 截圖 P1:pyenv 多版本 + shims 示意圖(投影片)

📣 「重點理解一件事:pyenv 沒有真的改你的系統 Python,它只是在你打指令時『插隊』,根據當前資料夾幫你選對版本。離開資料夾就恢復原狀。」

.python-version 這個檔案:跑 pyenv local 3.11.9 時自動產生,只有一行版本號。它告訴 pyenv「進到這個資料夾,請用這個版本」。要 commit 進 git,這樣團隊每個人 clone 下來版本就一致。

9-5. pipenv:Pipfile vs Pipfile.lock(重要觀念)

專案資料夾/
├── Pipfile          ← 你「想要」裝什麼套件(人寫、人看的)
├── Pipfile.lock     ← 實際「鎖定」的確切版本(機器產生,保證可重現)
└── (虛擬環境本體放在別的地方,pipenv 自動建、自動管)
檔案 角色 內容長相 誰來維護
requirements.txt(舊作法) 套件清單 requests==2.31.0(手動維護,容易漏) 你手動寫
Pipfile(pipenv 的清單) 套件清單 requests = "*"(你只說「我要 requests」) pipenv 幫你寫
Pipfile.lock(pipenv 的鎖檔) 確切版本快照 requests 2.31.0 + 連帶的 certifi、urllib3… 全部精確到版本與雜湊 pipenv 自動產生

📣 「Pipfile 像購物清單——你寫『我要買牛奶』。Pipfile.lock 像收據——記錄你實際買的是『某品牌 全脂 1 公升 批號 xxx』,連贈品(相依套件)都列上去。別人拿你的收據去買,買到的一模一樣。」

💡 lockfile 要 commit 進 git。它是「可重現性」的保證書——「在我電腦可以跑」變成「在每個人電腦都一樣」。


10. Lab 3:pyenv 安裝 + 操作

📂 現在在:~/projects/。

Step 1:安裝 pyenv 的相依套件

🪟 WSL / Ubuntu:

sudo apt update
sudo apt install -y make build-essential libssl-dev zlib1g-dev \
  libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
  libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev \
  libffi-dev liblzma-dev

📣 「pyenv 安裝 Python 的方式是從原始碼編譯,需要一堆 C 函式庫(上面那串)。一次裝好,之後每個 Python 版本才能順利編譯。」

✅ 預期:跑完沒有紅色錯誤

🍎 Mac:brew install openssl readline sqlite3 xz zlib tcl-tk

Step 2:安裝 pyenv

curl https://pyenv.run | bash

📣 「這行從官方腳本下載 pyenv 本體,裝到家目錄的 ~/.pyenv,不會碰你的系統 Python。」

📸 截圖 P2:pyenv 安裝完成的輸出(紅框標出「要把 pyenv 加進 shell」的提示)

Step 3:設定 shell(讓終端機認得 pyenv)

🪟 WSL(bash):

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

🍎 Mac(zsh):把 ~/.bashrc 改成 ~/.zshrc

📣 「這三行:①告訴系統 pyenv 裝在哪 ②把 pyenv 的 shims 放進 PATH 最前面(才能攔截 python)③啟動 pyenv。」

Step 4:重新載入 shell + 確認

exec "$SHELL"
pyenv --version

✅ 預期:pyenv 2.x.x

📸 截圖 P3:pyenv –version 輸出

Step 5:安裝一個 Python 版本

pyenv install 3.11.9

⚠️ 這會從原始碼編譯,需要 3-5 分鐘,請耐心等,不要以為當機。

📸 截圖 P4:pyenv install 過程(標出「Installing Python-3.11.9…」+「這裡會等幾分鐘」)

✅ 預期:最後出現「Installed Python-3.11.9」

Step 6:在專案資料夾設定版本(重點)

cd ~/projects
pyenv local 3.11.9
cat .python-version
python --version

✅ 預期:

  • .python-version 內容是 3.11.9
  • python --version 顯示 Python 3.11.9(在這個資料夾自動切換了!)

📸 截圖 P5:pyenv local + .python-version + python –version

  • 紅框①標出 .python-version 內容
  • 紅框②標出 python --version 已是 3.11.9

📣 「神奇的地方:只要 cd 進有 .python-version 的資料夾,Python 自動變成那版(shims 在運作)。離開就變回系統的。記得 .python-version 要 commit。」

Step 7:pyenv 常見指令速查

指令 作用
pyenv versions 看裝了哪些版本(* 是現用)
pyenv install 3.x.x 安裝某版本
pyenv local 3.x.x 設定「當前資料夾」用哪版(產生 .python-version)
pyenv global 3.x.x 設定「全機預設」用哪版
pyenv which python 看現在的 python 到底是哪個檔案

11. Lab 4:pipenv 虛擬環境

Step 1:安裝 pipenv

pip install --user pipenv
pipenv --version

📣 「--user 裝到你的使用者目錄,不需要 sudo、不污染系統。」

✅ 預期:pipenv, version x.x.x

⚠️ 如果 pipenv: command not found:

echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
exec "$SHELL"

Step 2:用指定 Python 版本建虛擬環境

cd ~/projects
pipenv --python 3.11.9

📣 「--python 3.11.9 告訴 pipenv:『用 pyenv 剛裝的 3.11.9 建虛擬環境』。看到沒——pyenv 管版本、pipenv 拿來建環境,兩個工具就是這樣合作。」

📸 截圖 P6:pipenv 建虛擬環境的輸出

  • 紅框①標出指令
  • 紅框②標出「Successfully created virtual environment!」

✅ 預期:產生一個 Pipfile(5-9-5 講的「購物清單」)

Step 3:裝一個套件,看 lockfile 產生

pipenv install requests

📣 「跑這行時 pipenv 做了三件事:①裝 requests 進虛擬環境 ②把 requests = "*" 寫進 Pipfile ③產生 Pipfile.lock,把確切版本鎖起來。」

📸 截圖 P7:pipenv install requests 的輸出(標出「Adding requests to Pipfile」+「產生 Pipfile.lock」)

打開 lockfile 感受「收據」長怎樣:

head -30 Pipfile.lock

📣 「Pipfile 你只寫了 requests,但 Pipfile.lock 裡是精確版本號加一長串雜湊值(hash)。這就是『可重現』的底氣。」

📸 截圖 P8:Pipfile.lock 內容(標出精確版本號與 hash)

Step 4:進虛擬環境執行

pipenv run python -c "import requests; print(requests.__version__)"

📣 「pipenv run 表示『用這個專案的虛擬環境執行』。requests 只裝在這個專案的盒子裡,不污染系統 Python。」

✅ 預期:印出 requests 版本號(例如 2.31.0),沒有 ModuleNotFoundError

📸 截圖 P9:pipenv run + import requests 成功

Step 5:pipenv 常見指令速查

指令 作用
pipenv --python 3.x.x 用指定版本建虛擬環境
pipenv install <套件> 裝套件並寫進 Pipfile + 更新 lock
pipenv install --dev <套件> 裝「開發用」套件(如 pytest),歸到 dev 區塊
pipenv install 照 Pipfile.lock 一鍵還原整個環境(同事 clone 後就跑這個)
pipenv run <指令> 用虛擬環境執行某指令
pipenv shell 進入虛擬環境(之後打指令不用加 pipenv run)
pipenv graph 看相依樹