除錯與測試:找出程式的病
進階錯誤三類:語法(格式錯、無法啟動)、運行時(跑到一半停,如除以零)、邏輯(跑完但結果錯);用已知答案的測試資料驗證,用 print 和追蹤表找變數問題。
- 錯誤三類:語法、運行時、邏輯。
- 語法錯誤啟動不了;運行時錯誤跑到一半停;邏輯錯誤跑完但結果錯。
- 錯誤訊息最後一行講類型,上面講行號 — 先讀訊息再動手。
文體小知識:方法指導課教你一套有系統的做法,照步驟練習,遇到問題就不會毫無頭緒。
§課文原文 Passage
1程式出錯是家常便飯,找出並修正錯誤的過程叫除錯(Debugging)。錯誤分三大類:語法錯誤(Syntax error)— 寫錯格式,例如漏了冒號,程式一行都跑不到;運行時錯誤(Runtime error)— 執行到一半才停下,例如除以零或存取不存在的索引;邏輯錯誤(Logic error)— 程式順利跑完,但結果不對,例如把加寫成乘,最難察覺。
2Python 會直接告訴你語法和運行時錯誤:SyntaxError: invalid syntax、ZeroDivisionError: division by zero。看懂錯誤訊息的最後一行(錯誤類型)和上面的行號(出事位置),問題已經解決了一半。讀錯誤訊息是每個程式員的基本功。
3邏輯錯誤電腦不會報錯,要靠自己測試(Testing):用已知道答案的資料試跑,例如計平均分的程式,輸入 [10, 20, 30] 應該得出 20;如果得出 6000(不小心乘了),就知道出了問題。這些「先知答案、再驗證」的資料叫測試資料(Test data),還要包括邊界情況:空清單、全 0、只有一個數。
4逐步追蹤(Trace)是基本功:拿一張紙,一行一行寫下每個變數的變化,例如 n=1 → 印 1 → n=2 → 印 2 → n=3 → 印 3 → n=4 條件不成立結束;也可以在程式中間加 print(n) 觀察變數。養成「小改一步、測一次」的習慣,錯誤就不會積少成多。
1重點摘要 Summary
錯誤三類:語法(格式錯、無法啟動)、運行時(跑到一半停,如除以零)、邏輯(跑完但結果錯);用已知答案的測試資料驗證,用 print 和追蹤表找變數問題。
2生字卡 Vocabulary
程式中的錯誤或缺陷,令程式不能運行或結果不對。
找出錯誤位置和原因,並加以修正的過程。
程式格式不符合語言規則(如漏冒號),令程式完全無法啟動。
程式執行到一半才發生的錯誤,例如除以零、索引超出範圍。
程式順利執行完畢,但因演算法寫錯而得出錯誤結果,最難發現。
Python 顯示的錯誤報告:最後一行是錯誤類型,上面有出事的行號。
答案已知的輸入資料,用來驗證程式是否正確,包括邊界情況。
逐行記錄變數數值變化的表格,用來找出邏輯出錯的位置。
輸入範圍極端的情況:最小值、最大值、0、空清單、只有一個元素。
3逐步講解 Steps
- 辨認語法錯誤語法錯誤是程式的「文法」寫錯了,例如 if x > 5 漏了結尾的冒號,或者 print('hi' 漏了右括號,Python 都會報 SyntaxError。特徵非常明顯:程式無法執行任何一行,一啟動便報錯,錯誤訊息會指出出事的行號。初學者最常犯的是漏冒號、括號不配對,以及中英文標點混用,例如輸入了全形冒號。見到 SyntaxError,先檢查該行和上一行的符號是否齊全。
- 辨認運行時錯誤運行時錯誤是程式執行到一半才發生的錯誤,例如 10 / 0 會報 ZeroDivisionError;清單 [1, 2] 只有兩個元素,卻取第 6 個位置的元素(索引 5),便會報 IndexError,因為索引 5 並不存在。特徵是:程式能夠啟動,執行到某一句時突然停止,錯誤訊息會指出停在哪一行。處理方法:按行號找到該句,檢查除數是否可能為零、索引是否超出範圍、檔案是否存在等。
- 辨認邏輯錯誤邏輯錯誤最危險:程式正常跑完,沒有任何報錯,但答案不對。例如想計平均數,卻寫成 sum(nums) * len(nums),輸入 [10, 20, 30] 時輸出 1800,而不是正確的 20。電腦不會提醒你,唯一辦法是用已知道答案的資料測試。常見的邏輯錯誤還包括把加寫成乘、把 >= 寫成 >、循環次數差一。養成測試習慣,邏輯錯誤便無所遁形。
- 讀懂錯誤訊息Python 的錯誤訊息是最有用的線索。例如螢幕出現 ZeroDivisionError: division by zero,還附有一個行號:最後一行講錯誤類型,上面的行號指出哪一行出事。閱讀次序是先看最後一行知道錯誤類型,再按行號找到位置,檢查那句程式碼。看懂錯誤訊息是每個程式員的基本功,遇到不明白的錯誤名稱,可以先搜尋它的意思,再對照自己的程式碼逐步修正。
- 用測試資料驗證測試資料是「先知道答案、再驗證程式」的資料。以計平均數的程式為例:用 [10, 20, 30] 測試,心算答案 20;用 [5] 測試,只有一個數,答案 5;用 [0, 0] 測試,答案 0。正常值、單一值、邊界值全部都要試,因為不同情況觸發的錯誤不同,例如只有一個數時,某些寫法便會出錯。考試常要求列出測試資料和解釋原因,答題時每組資料都要寫明預期輸出。
- 紙筆追蹤表追蹤表是找出邏輯錯誤的基本功。拿一張紙畫表格,一行一行記錄每個變數的變化。例如 n = 1,程式是 while n < 4: print(n),然後 n = n + 1:第一圈 n 是 1,印出 1;第二圈 n 是 2,印出 2;第三圈 n 是 3,印出 3;第四圈 n 是 4,條件不成立,結束。變數由哪一圈開始與預期不符,表格一目了然,錯誤的位置便無所遁形。
- print 除錯法結果不對時,可以在關鍵位置加入 print 觀察中間值,例如 print('總分:', total),看看總分究竟是多少,從而判斷問題出在前半還是後半。找到問題之後,把這些臨時 print 刪除,保持程式整潔。最重要的原則是:小改一步、測一次,不要一次改五處,否則根本無法知道哪一個修改有效。遵守這個紀律,除錯便會事半功倍。
4圖解 Diagrams
5例題示範 Example
例題:以下程式想計算 [8, 9, 10] 的平均,但輸出 27。找出錯誤類型並修正。程式碼:total = 0;for s in [8, 9, 10]: total = total + s;average = total * 3;print(average)。
- 先分類:程式能夠跑完,全程沒有報錯,所以排除語法錯誤和運行時錯誤,剩下的是邏輯錯誤。
- 用測試資料心算驗證:8 + 9 + 10 = 27,總分正確;但題目要的是平均,27 其實是總分而非平均。
- 逐行檢查,找到問題行:average = total * 3 把乘號用錯了位置,應該是 average = total / 3。
- 修正後測試:27 除以 3 等於 9.0,正確;再用 [10, 20, 30] 驗證一次,輸出 20,通過測試。
- 答案:這是邏輯錯誤:程式沒有報錯但結果不對。把 average = total * 3 改為 average = total / 3,輸出變成 9.0;再用 [10, 20, 30] 測試得 20,兩組測試資料都通過,修正完成。
6常見錯誤 Mistakes
75 題快測 Quick check
Q1print("hello(漏了右括號)屬於哪類錯誤?
Q2執行 10 / 0 會發生什麼事?
Q3程式順利跑完,但平均分計錯。這是哪類錯誤?為什麼最難發現?
Q4想驗證計平均的程式,輸入 [10, 20, 30] 時應該期望什麼結果?
Q5寫出除錯的三個好方法(任何三個)。
8重點回顧 Recap
- 錯誤三類:語法、運行時、邏輯。
- 語法錯誤啟動不了;運行時錯誤跑到一半停;邏輯錯誤跑完但結果錯。
- 錯誤訊息最後一行講類型,上面講行號 — 先讀訊息再動手。
- 用已知答案的測試資料驗證,邊界情況也要試。
- 除錯習慣:小改一步、測一次;善用 print 和追蹤表。