M1 環境
- 說出直譯器、套件、虛擬環境各自是甚麼;
- 用 uv 建立課程專案,裝好 PyYAML 和 JupyterLab;
- 用
sys.executable查出現在執行的是哪一個 Python; - 分清
pyproject.toml、uv.lock、.venv的用途,知道哪些要交給別人、哪些不用。
1「我的電腦上可以執行」為甚麼不夠 Why "it works on my machine" is not enough
M0 的練習裏有一行 import yaml。把同一個 notebook 拿到一部新電腦上執行,很可能第一格就出錯:
ModuleNotFoundError: No module named 'yaml'
程式沒有寫錯。出錯的原因是那部電腦的 Python 沒有安裝 yaml 這個套件。一段 Python 程式能不能執行,不只看程式本身,還要看它在哪一個 Python 上執行,以及那個 Python 裝了哪些套件。
這個單元要解決的就是這件事:讓每個學生、每部電腦都有同一套 Python 和同一套套件。
2三樣東西:直譯器、套件、虛擬環境 Interpreter, packages, virtual environment
| 名稱 | 它是甚麼 | 比喻 |
|---|---|---|
| 直譯器(interpreter) | 執行 Python 程式的程式,即是你輸入 python 時啟動的那一個 |
廚房的爐頭 |
| 套件(package) | 別人寫好、可以安裝來用的程式碼,例如讀 YAML 的 PyYAML | 廚具和材料 |
| 虛擬環境(virtual environment) | 一個專案專用的資料夾,裏面有一個直譯器和這個專案的套件 | 每道菜各自一個工作枱 |
為甚麼要虛擬環境?如果所有專案都把套件裝在同一個地方,甲專案要 2.0 版、乙專案要 1.0 版,兩者就會互相覆蓋。每個專案有自己的工作枱,就不會互相影響;工作枱弄亂了,拆掉重建也不影響其他專案。
本課用 uv 管理這三樣東西。它是一個工具,負責下載合適版本的 Python、為專案建立虛擬環境、安裝套件,而且在 Mac 和 Windows 上的命令完全一樣。
flowchart LR
A["<b>uv init --bare</b><br/>pyproject.toml"] --> B["<b>uv add pyyaml jupyterlab</b><br/>uv.lock、.venv"]
B --> C["<b>uv run jupyter lab</b><br/>JupyterLab 開啟"]
classDef cmd fill:#ffffff,stroke:#d3d1cb,color:#37352f
class A,B,C cmd
3安裝 uv Install uv
uv 只要安裝一次。打開終端機(Mac:「終端機」App;Windows:開始選單搜尋「PowerShell」),輸入對應的命令:
Mac
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows(PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
裝好後,關掉終端機再重新打開,然後確認:
uv --version
看到 uv 0. 開頭的版本號就成功了。
安裝程式會把 uv 的位置加進系統的搜尋路徑(PATH),但只對新開的終端機有效。看到 command not found: uv(Mac)或「無法辨識 uv」(Windows),先關掉終端機再開一次。
你不用另外安裝 Python。下一步 uv 發現電腦裏沒有合適的 Python 時,會自動下載一個。
4建立課程專案 Create the course project
整門課的練習都放在同一個專案資料夾裏。在終端機逐行輸入:
mkdir python-course
cd python-course
uv init --bare
uv add pyyaml jupyterlab
mkdir建立資料夾,cd走進去;uv init --bare把這個資料夾變成一個 Python 專案;uv add安裝套件,並把它記錄在專案的清單裏。第一次會下載不少東西,等它完成即可。
完成後,資料夾裏多了三樣東西:
| 名稱 | 是甚麼 | 要交給別人嗎? |
|---|---|---|
pyproject.toml |
專案的說明:需要哪個版本的 Python、直接用到哪些套件 | 要 |
uv.lock |
鎖定檔:每一個套件(包括套件自己需要的套件)的準確版本 | 要 |
.venv/ |
虛擬環境:直譯器和已安裝的套件 | 不用 |
pyproject.toml 是寫給人看的,打開它會看到你剛才加的兩個套件:
[project]
name = "python-course"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"jupyterlab>=4.6.4",
"pyyaml>=6.0.3",
]
(版本號會隨你安裝的時間而不同。)
.venv 可以隨時刪除。下一次執行 uv run,uv 會按 uv.lock 重新建立一個一模一樣的。所以交給別人的是清單(pyproject.toml+uv.lock),不是 .venv 本身。對方在自己的電腦上執行 uv sync,就得到同一個環境。
環境不是「裝好就算」,而是「寫得下來、重建得出」。pyproject.toml 和 uv.lock 就是那份寫下來的紀錄。
5哪一個 Python? Which Python?
同一部電腦上,常常不只一個 Python:作業系統可能自帶一個,你以前可能裝過 Anaconda 或從 python.org 下載過一個,現在 uv 又為專案準備了一個。在終端機輸入 python3,啟動的是哪一個,要看系統的搜尋路徑;而在專案資料夾裏用 uv run,啟動的一定是專案 .venv 裏的那一個。
要查出現在執行的是哪一個,用 sys.executable:
uv run python -c "import sys; print(sys.executable)"
輸出會是專案資料夾裏 .venv 下的路徑,例如:
/Users/you/python-course/.venv/bin/python (Mac)
C:\Users\you\python-course\.venv\Scripts\python.exe (Windows)
把命令開頭的 uv run 拿走,直接執行 python3 -c "…"(Windows 用 python),結果多半是另一條路徑,甚至找不到 Python。這就是 M1 開頭那個 ModuleNotFoundError 的真正原因:程式在一個沒有裝 yaml 的 Python 上執行。
uv run python、uv run jupyter lab:前面加上 uv run,就保證用的是專案的 Python 和套件。直接輸入 python、pip install 或 jupyter lab,用的是搜尋路徑上的那一個,裝的套件也會落到別處。
6開啟 JupyterLab Open JupyterLab
在專案資料夾裏執行:
uv run jupyter lab
瀏覽器會自動打開 JupyterLab,左邊的檔案列表就是專案資料夾。要停止時,回到終端機按 Ctrl+C。
在這裏打開的 notebook,用的就是專案 .venv 裏的 Python,所以 import yaml 一定成功。把 M0 的三個練習檔複製到這個資料夾,再執行一次 m0-first-look.ipynb,這次是在你自己的環境裏執行。
7容易混淆 Easily confused
| 這兩樣 | 分別 |
|---|---|
uv add 和 import |
uv add 在終端機執行,把套件安裝進環境;import 寫在程式裏,把已安裝的套件載入來用。沒有先安裝,import 就會報 ModuleNotFoundError。 |
| 套件名稱和 import 名稱 | 安裝時叫 pyyaml,程式裏寫 import yaml。兩者不一定相同,以套件的說明文件為準。 |
pyproject.toml 和 uv.lock |
前者寫「要甚麼」(PyYAML 6 或以上),給人讀和改;後者寫「實際裝了甚麼」(PyYAML 6.0.3 和它需要的一切),由 uv 生成,不要手改。 |
| 全域安裝和虛擬環境 | 全域安裝把套件裝進搜尋路徑上那個 Python,所有專案共用;虛擬環境只屬於一個專案。本課一律用虛擬環境。 |
requirements.txt 和 pyproject.toml |
別人的專案常用 requirements.txt 列出套件。收到這樣的檔案,在自己的專案裏用 uv add -r requirements.txt 安裝即可。 |
理工科的課程和實驗室常用 Anaconda 或 Miniforge 裏的 conda。它和 uv 做的是同一類事:管理直譯器、套件和環境。兩者都可以用,但不要在同一個專案裏混用。本課統一用 uv。
8動手:查出你的 Python Hands-on: find your Python
- 按上面的步驟安裝 uv、建立
python-course專案; - 下載
m1-which-python.ipynb,放進python-course資料夾; - 執行
uv run jupyter lab,打開這個 notebook,逐個 cell 執行。
notebook 會印出你正在用的 Python 的路徑和版本,以及環境裏裝了多少個套件。最後一題請你刪除 .venv 再重新開啟,親眼看看 uv 怎樣把環境重建出來。
m1-numpy-eng.ipynb:用 uv add numpy matplotlib 加入兩個科學計算套件,確認版本,再用 M0 的感測器讀數畫一張折線圖。最後把 pyproject.toml 和 uv.lock 複製到另一個資料夾,用 uv sync 重建出同一個環境。需要 M0 的 sensor.json。
M2 會深入 JupyterLab:notebook 和 kernel 的分別,以及為甚麼「執行次序」會令結果無法重現。