Semorphe

例外

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

你會學到三件事

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

開始之前

第 3 課那件事還記得嗎——

n = int(input())

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

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

一、try / except

try:
    n = int("abc")
    print("轉成了", n)
except ValueError:
    print("那不是數字")
print("程式繼續")

輸出:

那不是數字
程式繼續

流程:

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 後面永遠寫出你要接的那一種

四、完整的形狀

try:
    n = int(input())
except ValueError:
    print("不是數字")
else:
    print("成功讀到", n)      # 沒出事才跑
finally:
    print("不管有沒有出事都跑")
什麼時候
try 可能出事的那一段
except X 出的是 X 的話
else 沒有出事的話(少用)
finally 不管怎樣都跑——關檔案之類的收尾

五、什麼時候該用它

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

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

完成的樣子

try:
    n = int("abc")
    print("轉成了", n)
except ValueError:
    print("那不是數字")
print("程式繼續")

換你了

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

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

這一課你做了什麼

如果卡住了

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