Python 環境:pyenv+pipenv
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.9python --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 |
看相依樹 |

送件鴿飛出去了