Semorphe

例外

錯誤不是當機,是一條可以走的路。 · ⏱ 約 25 分鐘

你會學到三件事

  1. try / except 接住錯誤,讓程式繼續
  2. 錯誤有名字,而名字就是它的種類
  3. 🔴 不要接住你不打算處理的東西

開始之前

第 3 課那件事還記得嗎:

n = int(input())

使用者打 abc 的話,程式當場停掉,後面全部不跑。

而使用者打錯字本來就會發生。那不是 bug,是你的程式該想過的情況。

🟢 先把編輯器打開,跟著下面一起做:跟著做

一、try / except

照著打上這一段:

1try:2    n = int("abc")3    print("轉成了", n)4except ValueError:5    print("那不是數字")6print("程式繼續")
"abc"把轉成整數"轉成了"變數n印出設定n為"那不是數字"印出遇到ValueError就把它叫做,然後"程式繼續"印出嘗試沒出錯才最後一定12635

輸出:

那不是數字
程式繼續

積木盤上 try 那一顆寫著「嘗試 …」,而它還有兩格: 「沒出錯才 …」與「最後一定 …」(第四節會用到)。

流程:

try 裡面出事的那一刻 → 剩下的【立刻跳過】 → 跳到 except → 之後正常往下走

⚠️ 出事那一行後面的東西不會跑,上面的 print("轉成了", n) 一次都沒印。

二、錯誤有名字

名字 什麼時候
ValueError 值不對——int("abc")
TypeError 型別不對——"a" + 1
KeyError dict 沒有那個鍵
IndexError 清單位置超出範圍
ZeroDivisionError 除以零
NameError 名字沒定義過

執行看看錯誤訊息,第一個字就是它的名字,那就是你要寫在 except 後面的。

拿到那個錯誤本身:

except ValueError as e:
    print("出事了:", e)

這一格在積木上讀起來就是它的意思:「遇到 … 就把它叫做 … 然後 …」。

三、🔴 不要接住你不打算處理的東西

下面這個寫法不要學,它會把所有錯誤都吞掉:

try:
    ...
except:              # 🔴 光禿禿的 except
    pass

這樣寫會接住所有東西,包括:

一個接住所有錯誤的程式, 和一個沒有錯誤的程式,看起來一模一樣。

而那正是最難查的一種 bug:它什麼都沒說,而它做錯了。

規則:except 後面永遠寫出你要接的那一種。

四、完整的形狀

四段合起來長這樣:

1try:2    n = int(input())3except ValueError:4    print("不是數字")5else:6    print("成功讀到", n)      # 沒出事才跑7finally:8    print("不管有沒有出事都跑")
讀一行輸入,提示把轉成整數設定n為"不是數字"印出遇到ValueError就把它叫做,然後"成功讀到"變數n印出"不管有沒有出事都跑"印出嘗試沒出錯才最後一定12684
什麼時候
try 可能出事的那一段
except X 出的是 X 的話
else 沒有出事的話(少用)
finally 不管怎樣都跑——關檔案之類的收尾

五、什麼時候該用它

✅  使用者輸入   本來就可能亂打
✅  讀檔案      檔案可能不存在
✅  網路        可能斷線
🔴  自己的邏輯錯誤  ← 那要【修】,不是接住

例外是給「本來就會發生的意外」用的, 不是給「我還沒想清楚」用的。

完成的樣子

這一課的參考做法——程式碼每一行的號碼,就印在對應的那塊積木上。

1try:2    n = int("abc")3    print("轉成了", n)4except ValueError:5    print("那不是數字")6print("程式繼續")
"abc"把轉成整數"轉成了"變數n印出設定n為"那不是數字"印出遇到ValueError就把它叫做,然後"程式繼續"印出嘗試沒出錯才最後一定12635

把積木打散,自己排回去:排回去:把剛才那支程式的積木排好

換你了

寫一個迴圈:一直要求使用者輸入數字,打錯就重問,打對才往下走。

提示:while True: + try + 成功就 break。

到編輯器做這一題:練習:打錯就重問,打對才往下走

做一個

一直讀,直到使用者打的是一個整數為止,然後印出它的兩倍。 打錯的時候印「那不是整數,再試一次」。

⚠️ 裁判先打 abc 再打 21。 🔴 except 後面要寫那個錯誤的名字,不要寫一個空的。 空的會把你沒打算處理的錯也吞掉。

到編輯器做這一題:做一個:問到對為止

這一課你做了什麼

如果卡住了

你看到 多半是因為
還是當掉了 except 的種類不對。先用 except Exception as e: print(e) 看看是什麼
try 裡面有些行沒跑 出事那一行後面的都會跳過,那是正常的
程式安靜地做錯事 用了光禿禿的 except,把真的 bug 也吞了
SyntaxError try 不能單獨存在,一定要配 except 或 finally
在編輯器打開這一課 →