M2 JupyterLab
- 認出 JupyterLab 介面的主要部分,熟練 cell 的基本操作;
- 說出 notebook(檔案)和 kernel(記憶體)各自保存甚麼;
- 從左邊的
[n]編號看出一個 notebook 曾經怎樣被執行; - 用「重新啟動並全部執行」確認結果是可信的。
1JupyterLab 的介面 The JupyterLab interface
在 M1 建立的 python-course 資料夾裏執行 uv run jupyter lab,瀏覽器會打開下面這個畫面:

| 位置 | 是甚麼 | 常用來 |
|---|---|---|
| 左邊 | 檔案瀏覽器,顯示專案資料夾 | 雙擊打開檔案;按 + 打開 Launcher,在 Notebook 一行選「Python 3 (ipykernel)」新增 notebook |
| 上方分頁 | 每個打開的檔案一個分頁 | 同時打開幾個 notebook、YAML 檔 |
| 工具列 | 儲存、新增 cell、執行、停止、重新啟動 | 最右邊顯示這個 notebook 用的 kernel |
| 中間 | 一格一格的 cell | 寫程式和說明 |
| 狀態列 | 最下面一行 | 看 kernel 是 Idle(閒置)還是 Busy(執行中) |
檔案瀏覽器裏,名稱前面有綠點的 notebook,代表它已經打開、有 kernel 在背後執行;分頁上的叉號變成圓點,代表有未儲存的改動。
2兩種 cell,兩種模式 Two kinds of cell, two modes
notebook 由 cell 組成,最常用的有兩種:
- code cell:寫 Python。執行後,結果顯示在它下面,左邊出現
[n]編號; - Markdown cell:寫說明文字,可以有標題、清單、粗體,甚至數學式。執行它就是把文字排好版顯示出來。
操作 cell 時有兩種模式,分別在於鍵盤輸入去了哪裏:
- 編輯模式:cell 裏有游標,輸入的是 cell 的內容。按
Enter或點進 cell 進入; - 命令模式:沒有游標,按鍵是對整格 cell 下命令。按
Esc進入。
| 按鍵 | 模式 | 作用 |
|---|---|---|
Shift+Enter |
兩者皆可 | 執行這一格,跳到下一格 |
Esc/Enter |
— | 切換到命令模式/編輯模式 |
A/B |
命令 | 在上面/下面插入一格 |
D D(按兩下) |
命令 | 刪除這一格 |
M/Y |
命令 | 把這一格改成 Markdown/code |
Z |
命令 | 復原剛才刪除的 cell |
在命令模式下打字,字母會被當成命令:按了 D 兩下就刪掉了一格,按了 M 就把程式變成了文字。打字前先看清楚 cell 裏有沒有游標;刪錯了就在命令模式按 Z。
3notebook 和 kernel The notebook and the kernel
打開一個 notebook,其實同時有兩樣東西在運作:
- notebook 是
.ipynb檔案,保存每一格的程式碼、上次執行的輸出,以及左邊的編號。它只是一份紀錄。 - kernel 是一個在背後執行的 Python,所有變數都在它的記憶體裏。在 M1 的專案裏,它就是
.venv那一個 Python。
兩者各自獨立,所以:
- 儲存 notebook,不會保存變數。 關掉 JupyterLab 再打開,輸出還在,但 kernel 是新的,記憶體是空的。要用變數,得重新執行。JupyterLab 預設每 2 分鐘自動儲存一次,所以「不儲存就關掉」不一定能撤銷改動;想保留舊版本,用 Git(git-course)。
- 關掉 notebook 分頁,kernel 不一定停止。 它可能仍在背後佔用記憶體。要停止,選
Kernel→Shut Down Kernel。 - 重新啟動 kernel,檔案不會改變。 程式碼和舊的輸出都還在,只是記憶體清空了。
看到的輸出,是上一次執行時的結果,不一定是「現在這段程式碼」的結果。
4執行次序 Execution order
每執行一次 code cell,kernel 就把計數加一,寫在那一格左邊:第一次執行的是 [1],第二次是 [2],如此類推。執行中的那一格顯示 [*],從未執行過的顯示 [ ]。
一格 cell 執行了很久還是 [*](例如 M5 學迴圈時,寫了一個停不下來的迴圈),按工具列上的 ■,或者選 Kernel → Interrupt Kernel,就會中斷它,並顯示 KeyboardInterrupt。中斷只停下這一格,記憶體裏的變數仍在。按了還是停不下來,才用 Restart Kernel。
notebook 讓你可以按任何次序執行 cell,可以回頭修改再執行,也可以刪掉執行過的 cell。這是它方便的地方,也是問題的來源。下圖是一個真實會發生的情況:
在第②步,notebook 看起來完全正常:每一格都有輸出,也沒有錯誤訊息。但是:
- 第二格寫着
0.9,記憶體裏的discount卻是0.8,所以後面的價錢全是按八折計算的; - 定義
tax_rate的那一格已經刪除了,變數卻仍留在記憶體裏,所以最後一格照樣得出答案。
把這個 notebook 傳給別人,對方一打開執行,就會得到不同的結果,甚至出錯。
要看出問題,線索就在左邊的編號:
- 編號跳號(
[4]之後是[6]):中間有一格執行過,後來被刪除或改動了; - 編號不是由上而下遞增(例如上面是
[7],下面是[3]):cell 不是按次序執行的; - 一格的輸出和它的程式碼對不上:這一格修改後沒有重新執行。
5重新啟動並全部執行 Restart and run all
解決的方法只有一個:清空記憶體,從第一格開始順序執行一次。選 Kernel → Restart Kernel and Run All Cells…,或者按工具列上的 ⏩ 按鈕。
執行完,如果編號由 [1] 開始、由上而下逐一遞增,而且沒有任何錯誤,這個 notebook 的結果就是可信的:任何人照着執行,都會得到同樣的結果。
養成習慣,在以下時候做一次:
- 儲存並交給別人之前;
- 結果看起來不對勁的時候;
- 刪除或改名了一個變數之後。
Restart Kernel 只是清空記憶體,不會執行任何 cell;畫面上的舊輸出全部還在,看起來甚麼都沒變。要用的是 Restart Kernel and Run All Cells。
6容易混淆 Easily confused
| 這兩樣 | 分別 |
|---|---|
| notebook 和 kernel | notebook 是檔案,保存程式碼和上次的輸出;kernel 是執行中的 Python,保存變數。 |
| 儲存和重新啟動 | 儲存把畫面上的內容寫進檔案,不影響記憶體;重新啟動清空記憶體,不影響檔案。 |
Restart Kernel 和 Restart Kernel and Run All Cells |
前者只清空記憶體;後者清空之後由第一格順序執行全部 cell。 |
| code cell 和 Markdown cell | 前者交給 kernel 執行;後者只是排版文字,不經過 kernel。 |
[ ]、[*]、[5] |
從未執行、正在執行、第五次執行時執行了這一格。 |
7動手:一個有問題的 notebook Hands-on: a broken notebook
- 下載
m2-bookshop-order.ipynb和books.yaml,放進python-course資料夾; - 執行
uv run jupyter lab,打開這個 notebook。
這是一位同事傳來的 notebook,計算小書店現貨書打折後的總價,檔案裏保留了他上次執行的結果。先不要執行任何 cell,只看程式碼、輸出和編號,回答 notebook 最後的問題;然後才重新啟動並全部執行,找出並修好問題。
m2-lab-log-eng.ipynb:把 notebook 寫成一份實驗記錄。用 Markdown cell 寫目的、方法(包括一條數學式)和結論,用 code cell 計算 M0 感測器讀數的平均值和差距。其中一格被錯放成 code cell,你要把它改回 Markdown。需要 M0 的 sensor.json。
M3 開始學 Python 本身:數字、字串、布林值和 None,以及「變數只是名字」是甚麼意思。