文章

Python-12-try…except 錯誤捕捉—接住錯誤,不讓程式崩潰

零、前言

相信學到這邊,讀者在寫程式上,已經有遇過許多次的程式執行錯誤經驗了,這是學習程式的日常。

而在實務開發上,這類的錯誤,雖然難免會發生,但如果沒有預先考慮到我們的程式碼中,很容易會發生程式因此而中斷導致整個流程停擺的問題。

舉個生活化的例子:

今天你命令小明去幫你買早餐,小明按照著你的指令出門,穿過大街小巷,當走到早餐店門口時,突然發現,「早!餐!店!沒!開!」,這是預期之外的錯誤,如果沒做錯誤捕捉的情況下,小明直接放棄跑出去玩了,這樣你也無從得知最後到底有沒有買到早餐;如果有做錯誤捕捉的情況下,小明就會知道,當遇見早餐店沒開時,應開打電話通知你一聲,或者直接跑到下一間早餐店買早餐,有因應的方法,幫助我們處理非預期的問題,就是錯誤捕捉的意義。

一、try…except 語法說明

我們直接來看程式的架構:

1
2
3
4
5
6
7
8
9
10
11
12
try:
    # 要捕捉的程式碼段落
    # 主要防止這個區塊的程式碼出現非預期錯誤
    ...
except Exception as e:
    # 出現例外事件時,可以在這邊進行後續處理
    # 如果沒有出現例外事件就跳過這區塊
    ...
finally:
    # 無論是否出現例外情況,最後都要執行此區塊程式碼
    # 不一定要有 finally 的寫法,可以看情況使用,但前兩者語法必須有
    ...
  1. try…except…兩個關鍵字必須相輔相成,缺一不可
  2. except Exception as e代表出現了一個例外事件,不管它是什麼事件,都用一個Excepttion變數存著,然後給他一個簡稱叫做 e方便我們在程式碼區塊中使用
  3. finally 看狀況使用,不一定要寫

實際例子:

設計一個讓老師輸入學生成績,便可以輸出對應等第的成績系統

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 無限迴圈,會一直循環下去
while True:
    try:
        # 讓老師輸入成績,成績需要是數字
        my_score = int(input("請輸入學生成績:"))
        
        # 按照不同成績,給不同等第
        if my_score >= 90:
            print("等第:A")
        elif my_score >= 80:
            print("等第:B")
        elif my_score >= 70:
            print("等第:C")
        else:
            print("不及格!!")
    
    except Exception as e:
        # 捕捉到例外錯誤的情況下,輸出錯誤的訊息
        print(f"出現預期外錯誤,錯誤訊息:{e}")
        print("成績輸入無效...請重輸入")

輸出結果 輸出結果

  1. 程式因為在錯誤捕捉的情況下,偵測到輸入錯誤的情況,跳出通知提醒,並且不中斷程式,使迴圈循環可以繼續進行,這樣的設計是避免人為誤打資料的防呆機制
  2. print(e) 可以將錯誤的內容輸出,使用者便可以知道發生什麼錯誤

二、捕捉特定的錯誤事件

從上面例子來看,讀者可能會以為,不管發生任何錯誤,都只會跑到except Exception as e 裡吧?

實際上錯誤有分成很多種類型,而錯誤捕捉當然也可以做到細緻地捕捉各種不同錯誤,甚至只針對特定幾種錯誤進行個別處理,下面舉個例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
    a = 10
    b = 0  # 嘗試改成 0 或 "a" 測試不同的錯誤
    result = a / b
    print(f"計算結果是: {result}")
except ZeroDivisionError as zde:
    print(f"捕捉到 ZeroDivisionError: {zde}") # 針測到 除以0錯誤
except TypeError as te:
    print(f"捕捉到 TypeError: {te}") # 偵測到輸入非數字型態錯誤
except Exception as e:
    print(f"捕捉到其他 Exception: {e}") # 偵測到以上兩種之外錯誤
finally:
    print("程式執行完畢")
  • 改變 b 的值來測試不同的錯誤:
    • b 設為 0,會捕捉到 ZeroDivisionError
    • b 設為 "a",會捕捉到 TypeError
  • except ZeroDivisionError 捕捉除以零的錯誤
  • except TypeError 捕捉類型錯誤
  • except Exception as e 捕捉其他未預期的錯誤
  • finally 區塊無論是否發生錯誤都會執行,用於表示該段程式結束

實際上例外錯誤 Python 中有內建許多不同的類型,有興趣可參考官方文件:

內建的例外

三、結語

錯誤捕捉最常使用的情境就是,當程式可能受到外部事件影響其運作時,就需要將這個功能考慮進去,一樣用一開始請小明買早餐的例子,因為我們無法決定早餐店是否營業,因此我們請小明買早餐的行為就包含著早餐店是否營業的風險因素在,就需要有進一步的預防對策。

在程式世界很常會有這種狀況,例如:我們要到某網站抓取股市資訊、新聞資訊時,有可能對方網站突然更新、關站了,這些變動都可能使程式突然掛掉,這時候錯誤捕捉就是很好用的工具,可以讓程式在遇到例外問題時,執行別的解決方案,或者即時提供回報,這都有助於我們的管理。

本文章以 CC BY 4.0 授權