虛擬環境與 uv:讓環境可以重現
「在我電腦上明明可以跑」是最常見的麻煩。這堂課用 uv 幫記帳專案建立專屬的虛擬環境,把用到的套件寫進 pyproject.toml,讓任何人、任何電腦、任何 AI Agent 都能一鍵重現同一個環境。
「在我電腦上明明可以跑」
上一堂把記帳工具拆成了好幾個檔案。現在假設你想把它分享給同事,或是換一台新電腦繼續寫。你把資料夾複製過去,執行,然後:
ModuleNotFoundError: No module named 'pandas'
因為 pandas 是你當初用 pip install 裝在舊電腦上的,資料夾裡並沒有它。更麻煩的是,過了幾個月,你也記不得當時裝了哪些套件、哪個版本。
還有另一種狀況:你同時有兩個專案,一個需要舊版的某套件,另一個需要新版。全部裝在同一個地方,裝了新的,舊專案就壞了。
這些問題有一個共同的解法:虛擬環境。
虛擬環境:每個專案一個套件箱
虛擬環境(virtual environment)是放在專案資料夾裡的一個小空間,通常叫 .venv。這個專案需要的套件都裝在這裡,不會跑到電腦的其他地方,也不會影響別的專案。
你可以把它想成廚房裡的食材箱:做咖哩的箱子、做蛋糕的箱子分開放,互不干擾。而且只要有一張採購清單,箱子丟了也能照單重新買齊。
重點不是箱子本身,而是那張清單。有清單,箱子隨時可以重建。
Python 本身就能建虛擬環境(python -m venv .venv),但要記得「啟用」它、自己維護清單,步驟不少,新手很容易漏掉一步。這堂課我們用一個把這些事全部包辦的工具:uv。
認識 uv
uv 是一個 Python 的專案管理工具,速度很快,而且一次管好三件事:
- Python 版本:專案需要的 Python 版本,沒有的話它會幫你下載
- 虛擬環境:自動建立、自動使用
.venv,不用手動啟用 - 套件清單:裝了什麼套件,自動寫進清單
近來很多 Python 專案和 AI 工具的官方說明都改用 uv,學會它,你看別人的專案說明也會順很多。
安裝 uv
打開 uv 的官方文件(搜尋「uv astral install」),照你的作業系統複製安裝指令。寫這堂課時,官方提供的指令是:
# Windows(PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
# Mac
curl -LsSf https://astral.sh/uv/install.sh | sh
安裝指令偶爾會更新,以官方文件為準。裝好後關掉終端機再重開,輸入:
uv --version
看到版本號就成功了。如果顯示「找不到指令」,通常是終端機沒重開,或是需要重新開機一次。
三個指令就夠用
uv init:建立專案
找一個放專案的地方,執行:
uv init expense-tracker
cd expense-tracker
uv 會建立一個 expense-tracker 資料夾,裡面大概有這些(不同版本可能略有差異):
expense-tracker/
├── .git/ ← uv 順便幫你做了 git init,第 6 堂會用到
├── .gitignore
├── .python-version ← 這個專案用哪個 Python 版本
├── README.md
├── main.py ← 範例程式
└── pyproject.toml ← 專案的說明書和採購清單
接著,把上一堂整理好的 main.py、tracker 資料夾和 expenses.csv 複製進來。uv 產生的範例 main.py 直接用你的版本覆蓋掉即可。
pyproject.toml:專案的說明書
打開 pyproject.toml,你會看到類似這樣的內容:
[project]
name = "expense-tracker"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []
這是專案的設定檔,格式叫 TOML,一行一個設定,很好讀。requires-python 是這個專案需要的 Python 版本(數字依你電腦而定),dependencies 是依賴套件,也就是這個專案要用到的別人的套件。現在還是空的。
順手把 description 改成一句中文,例如「我的記帳小工具」。這種小事,對之後讀這個專案的人(和 AI)很有幫助。
uv add:加入套件
我們想讓記帳工具之後能匯出 Excel,需要 pandas 和 openpyxl:
uv add pandas openpyxl
這一行做了三件事:
- 第一次執行時,在專案裡建立
.venv虛擬環境 - 把 pandas 和 openpyxl 裝進
.venv - 把它們寫進
pyproject.toml的dependencies,並產生一個uv.lock
再打開 pyproject.toml 看看:
dependencies = [
"openpyxl>=3.1.5",
"pandas>=2.3.3",
]
版本號會跟你的不一樣,沒關係。>= 的意思是「至少要這個版本」。
不需要某個套件了,用 uv remove 套件名稱 移除,清單也會跟著更新。
uv run:在環境裡執行
uv run main.py
uv run 會確認環境和清單一致(缺什麼就補裝),然後用這個專案的 .venv 執行程式。你不用記得「啟用環境」,也不用擔心跑到別的 Python。從今天起,這個專案的程式都用 uv run 執行。
換一台電腦,一個指令還原
現在來驗證「可以重現」。把 .venv 資料夾整個刪掉(對,直接刪),然後執行:
uv sync
uv sync 會照著 uv.lock,把 .venv 一模一樣地重建出來。其實直接 uv run main.py 也會自動做這件事。
清單跟著專案走,環境在每台電腦上各自重建。
這代表兩件事:
- 要保存、要分享的:
pyproject.toml、uv.lock、.python-version,還有你的程式碼 - 不用保存、不要分享的:
.venv,它很大,而且隨時能重建。uv 產生的.gitignore已經幫你把它排除了
為什麼這對 AI Agent 特別重要
當你請 Claude Code 這類 AI Agent 幫你改專案,它會自己執行指令:跑程式、裝套件、跑測試。如果環境不清楚,常見的狀況是:
- 它用
pip install把套件裝到電腦全域,你的專案清單卻沒有更新 - 它用了另一個版本的 Python,跑出來的結果和你的不一樣
- 它說「測試通過了」,但換到你的電腦上卻跑不起來
uv 讓這些事變得單純:只有一個環境、一份清單、一種執行方式。你只要在專案說明檔(例如 Claude Code 會讀的 CLAUDE.md)裡寫清楚:
## 環境
- 這個專案用 uv 管理。執行程式用 uv run main.py。
- 要新增套件用 uv add,不要用 pip install。
- 不要手動修改 uv.lock。
Agent 每次開工都會先讀到這幾行,就知道該怎麼做。人類同事也一樣。
我的 Python 專案用 uv 管理(pyproject.toml 和錯誤訊息貼在下面)。執行 uv run main.py 時出現錯誤。請先判斷這是「套件沒裝」「Python 版本不對」還是「程式本身的問題」,再告訴我要執行哪個 uv 指令修正。請不要建議我用 pip install。
pyproject.toml:(貼上)
錯誤訊息:(完整貼上)
- 安裝 uv,用
uv init expense-tracker建立專案,把上一堂的main.py、tracker和expenses.csv搬進來,用uv run main.py確認能正常記帳。 - 執行
uv add pandas openpyxl,打開pyproject.toml確認dependencies多了兩行,資料夾裡多了uv.lock。 - 在
tracker/report.py加一個匯出功能,再從main.py的選單加一個選項3 匯出 Excel來呼叫它:
import pandas as pd
def export_excel(records, path="expenses.xlsx"):
pd.DataFrame(records).to_excel(path, index=False)
print(f"已匯出到 {path}")- 驗收「可以重現」:刪掉
.venv資料夾,執行uv sync,再用uv run main.py匯出一次 Excel。能成功,就代表你的專案已經可以在任何電腦上重建了。 - 在專案裡新增
CLAUDE.md,寫下上面那三行「環境」規則。
讀完了嗎?
標記完成後,單元與專案的進度會自動更新(只存在這台裝置的瀏覽器)。
留言與討論
卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。