Python 資料全景課 / 第一部分 建立心智模型 · M2

M2 JupyterLab

notebook 看起來像一份文件,背後卻有一個一直在執行的 Python。分清楚「檔案裏寫着甚麼」和「記憶體裏有甚麼」,就能避開 notebook 最常見、也最難察覺的錯誤。
約 40 分鐘練習 notebook 1 個(有問題的 notebook)先修:M1
學完本單元,你能夠:
  1. 認出 JupyterLab 介面的主要部分,熟練 cell 的基本操作;
  2. 說出 notebook(檔案)和 kernel(記憶體)各自保存甚麼;
  3. 從左邊的 [n] 編號看出一個 notebook 曾經怎樣被執行;
  4. 用「重新啟動並全部執行」確認結果是可信的。

1JupyterLab 的介面 The JupyterLab interface

在 M1 建立的 python-course 資料夾裏執行 uv run jupyter lab,瀏覽器會打開下面這個畫面:

圖 1 JupyterLab 的介面。左邊是檔案瀏覽器,右邊是打開了的 notebook;最上面是選單,notebook 上方是工具列,最下面是狀態列。
圖 1 JupyterLab 的介面。左邊是檔案瀏覽器,右邊是打開了的 notebook;最上面是選單,notebook 上方是工具列,最下面是狀態列。
位置 是甚麼 常用來
左邊 檔案瀏覽器,顯示專案資料夾 雙擊打開檔案;按 + 打開 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 組成,最常用的有兩種:

操作 cell 時有兩種模式,分別在於鍵盤輸入去了哪裏:

按鍵 模式 作用
Shift+Enter 兩者皆可 執行這一格,跳到下一格
Esc/Enter — 切換到命令模式/編輯模式
A/B 命令 在上面/下面插入一格
D D(按兩下) 命令 刪除這一格
M/Y 命令 把這一格改成 Markdown/code
Z 命令 復原剛才刪除的 cell
打字沒有反應,或者 cell 不見了

在命令模式下打字,字母會被當成命令:按了 D 兩下就刪掉了一格,按了 M 就把程式變成了文字。打字前先看清楚 cell 裏有沒有游標;刪錯了就在命令模式按 Z。

3notebook 和 kernel The notebook and the kernel

打開一個 notebook,其實同時有兩樣東西在運作:

圖 2 notebook 和 kernel 是兩樣東西。執行 cell 時,notebook 把程式碼送到 kernel;kernel 執行完,把輸出送回來。變數只存在 kernel 的記憶體裏。
圖 2 notebook 和 kernel 是兩樣東西。執行 cell 時,notebook 把程式碼送到 kernel;kernel 執行完,把輸出送回來。變數只存在 kernel 的記憶體裏。

兩者各自獨立,所以:

重點

看到的輸出,是上一次執行時的結果,不一定是「現在這段程式碼」的結果。

4執行次序 Execution order

每執行一次 code cell,kernel 就把計數加一,寫在那一格左邊:第一次執行的是 [1],第二次是 [2],如此類推。執行中的那一格顯示 [*],從未執行過的顯示 [ ]。

一直顯示 [*]:停止執行

一格 cell 執行了很久還是 [*](例如 M5 學迴圈時,寫了一個停不下來的迴圈),按工具列上的 ■,或者選 Kernel → Interrupt Kernel,就會中斷它,並顯示 KeyboardInterrupt。中斷只停下這一格,記憶體裏的變數仍在。按了還是停不下來,才用 Restart Kernel。

notebook 讓你可以按任何次序執行 cell,可以回頭修改再執行,也可以刪掉執行過的 cell。這是它方便的地方,也是問題的來源。下圖是一個真實會發生的情況:

圖 3 亂序執行的三個階段。①時檔案和記憶體一致;②改了程式碼、刪了一格,卻沒有重新執行,檔案和記憶體就對不上,但畫面上看不出問題;③重新啟動並全部執行,問題才浮現。
圖 3 亂序執行的三個階段。①時檔案和記憶體一致;②改了程式碼、刪了一格,卻沒有重新執行,檔案和記憶體就對不上,但畫面上看不出問題;③重新啟動並全部執行,問題才浮現。

在第②步,notebook 看起來完全正常:每一格都有輸出,也沒有錯誤訊息。但是:

把這個 notebook 傳給別人,對方一打開執行,就會得到不同的結果,甚至出錯。

要看出問題,線索就在左邊的編號:

5重新啟動並全部執行 Restart and run all

解決的方法只有一個:清空記憶體,從第一格開始順序執行一次。選 Kernel → Restart Kernel and Run All Cells…,或者按工具列上的 ⏩ 按鈕。

執行完,如果編號由 [1] 開始、由上而下逐一遞增,而且沒有任何錯誤,這個 notebook 的結果就是可信的:任何人照着執行,都會得到同樣的結果。

養成習慣,在以下時候做一次:

  1. 儲存並交給別人之前;
  2. 結果看起來不對勁的時候;
  3. 刪除或改名了一個變數之後。
只按「重新啟動」不夠

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

  1. 下載 m2-bookshop-order.ipynb 和 books.yaml,放進 python-course 資料夾;
  2. 執行 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,以及「變數只是名字」是甚麼意思。