跳到內容

錯誤處理

程式執行到一半,有時會遇到沒辦法處理的狀況:使用者把數字欄位填成文字、除數是 0、要開的檔案不存在……這些叫做錯誤(也叫異常,exception)。一發生,程式預設就會當場停下來報錯。這一章看怎麼接住這些錯誤,讓程式繼續好好走下去。

把可能出錯的程式放進 try,萬一真的出錯,就跳到 except 那段。下面這段做除法,如果除數填 0,本來會壞掉,但 except 把它接住了。按「執行」,除數輸入 0 試試:

try:
a = int(input("被除數:"))
b = int(input("除數:"))
print(a / b)
except ZeroDivisionError:
print("不能除以 0!")

把除數改成別的數字再送出一次,程式就走正常的路,except 那段完全不會碰到。它只在真的出錯時才會跑。

except 後面可以指定要接住哪一種錯誤。像 int("abc") 這種「轉不成數字」的情況會丟出 ValueError

try:
age = int(input("你的年齡:"))
print("明年你", age + 1, "")
except ValueError:
print("請輸入數字,不要輸入文字")

指定錯誤的種類是好習慣:你只接住預期中的錯誤,其他沒想到的問題還是會照常報出來,才不會把真正的 bug 藏起來。常見的錯誤還有 ZeroDivisionError(除以 0)、TypeError(型別用錯)、KeyError(字典沒有那個鍵)等等。

完整的結構還有兩段:

  • elsetry沒有出錯時才執行。
  • finally:不管有沒有出錯,最後一定會執行,常用來做收尾(例如關檔)。
try:
number = int(input("輸入一個數字:"))
except ValueError:
print("那不是數字")
else:
print("成功讀到", number)
finally:
print("結束(這行一定會執行)")

輸入 7 會走 else,再走 finally;如果輸入文字,就改走 except,一樣會走到 finally

除了接住錯誤,你也可以在該擋的地方主動丟出錯誤,用的是 raise。這常拿來擋不合理的輸入:

def set_age(age):
if age < 0:
raise ValueError("年齡不能是負的")
print("年齡設為", age)
set_age(25)
set_age(-3)

set_age(25) 正常印出,但 set_age(-3) 因為年齡是負的就 raise 了一個 ValueError。這裡沒有 try 去接它,所以程式就停下來、報出這個錯誤。這正是 raise 的用意:把不該發生的事情大聲講出來,而不是默默算下去。