Python 全攻略:第八節 - Error Handling and Exceptions (115-117)

目標

  • 掌握例外處理的基本概念和語法。
  • 理解 Python 中常見的例外類型。
  • 學習如何設計更高效的例外處理邏輯。
  • 理解例外處理的進階應用(如自訂例外)。

一、什麼是例外處理?

定義

  • 程式執行中,可能遇到 錯誤非預期事件(例如:檔案不存在、除以零)。
  • 例外處理讓程式能在遇到錯誤時,有計劃地進行 錯誤處理,而非直接崩潰。

為什麼需要例外處理?

  1. 提高程式穩定性。
  2. 提供更友好的錯誤訊息。
  3. 允許程式在錯誤後繼續執行。

範例:基本例外處理

python

try:
    x = 10 / 0  # 會引發 ZeroDivisionError
except ZeroDivisionError:
    print("Cannot divide by zero.")

二、例外處理的基本語法

語法結構

python

try:
    # 可能引發錯誤的程式碼
except <ExceptionType>:
    # 錯誤處理邏輯
else:
    # 如果沒有發生錯誤,執行此區塊
finally:
    # 無論是否發生錯誤,都執行此區塊

語法解析

  1. try:包含可能引發錯誤的程式碼。
  2. except:捕捉特定的錯誤並處理。
  3. elsetry 區塊無錯誤時執行。
  4. finally:必定執行,用於清理資源(如關閉文件)。

三、例外處理的應用與進階

1. 捕捉多個例外

  • 可以使用多個 except,針對不同例外執行不同邏輯:

python

try:
    lst = [1, 2, 3]
    print(lst[10])  # 會引發 IndexError
except IndexError:
    print("Index out of range.")
except KeyError:
    print("Key not found.")

2. 常見例外類型

以下是常見例外類型,透過範例加深理解:

例外類型 範例 解釋
TypeError print("a" ** 2) 不匹配的資料型態操作
NameError print(undeclared_variable) 使用未定義變數
IndexError lst = [1]; print(lst[10]) 索引超出範圍
KeyError d = {"a": 1}; print(d["b"]) 字典鍵不存在
ValueError int("abc") 無法轉換的數值
FileNotFoundError open("nonexistent.txt") 檔案不存在
RecursionError 遞迴函式無終止條件,導致堆疊溢位(stack overflow)

3. 使用 elsefinally

  • elsetry 區塊沒有錯誤時執行。
  • finally:無論有無錯誤,最後執行。

範例

python

try:
    result = 10 / 2
except ZeroDivisionError:
    print("Cannot divide by zero.")
else:
    print("Calculation successful:", result)
finally:
    print("End of calculation.")

4. 例外處理的順序

例外處理的順序至關重要,必須先捕捉子類型例外,再捕捉父類型例外:

python

try:
    lst = [1, 2, 3]
    print(lst[4])  # IndexError
except LookupError:
    print("This is a lookup error.")  # 父類型
except IndexError:
    print("This is an index error.")  # 子類型,永遠不會被執行

四、例外處理策略:LBYL vs EAFP

LBYL (Look Before You Leap)

  • 先檢查後執行,適用於需要預測錯誤的場景。
  • 範例

python

def safe_divide(x, y):
    if y == 0:
        print("Cannot divide by zero.")
        return None
    return x / y

EAFP (Easier to Ask Forgiveness than Permission)

  • 先執行後處理,適用於簡化程式碼的場景。
  • 範例

python

def safe_divide(x, y):
    try:
        return x / y
    except ZeroDivisionError:
        print("Cannot divide by zero.")
        return None

五、進階應用:自訂例外

1. 自訂例外類型

  • 自訂例外類型可用於特定業務邏輯。

python

class NegativeNumberException(RuntimeError):
    def __init__(self, number):
        super().__init__(f"Negative number detected: {number}")

2. 與業務邏輯結合

  • 範例

python

def check_number(number):
    if number < 0:
        raise NegativeNumberException(number)
    print("Valid number:", number)

try:
    check_number(-5)
except NegativeNumberException as e:
    print(e)

六、課堂練習

基礎練習

  1. 寫一個函式,判斷輸入是否為整數,若否則提示用戶重新輸入。

python

def ask_for_int():
    while True:
        try:
            num = int(input("Enter an integer: "))
            print(f"You entered: {num}")
            break
        except ValueError:
            print("This is not an integer. Please try again.")
ask_for_int()

進階練習

  1. 自訂例外,處理輸入負數的情況,並計算輸入數值的平方。

挑戰題

  1. 設計一個成績管理系統,若輸入的成績超過範圍,則引發例外,並提示重新輸入。
3 Likes

自訂例外類型

class NegativeNumberException(RuntimeError):
    def __init__(self, number):
        super().__init__(f"Negative number detected: {number}")

def process_numbers(numbers):
    for number in numbers:
        if number < 0:
            raise NegativeNumberException(number)

process_numbers([1, 2, -3, 4, -5])
2 Likes

Python 3: Deep Dive (Part 4 - OOP) 中有 exception 的詳細介紹:

相關簡介和 github source code:

關於 Custom Exceptions:

也可以參考第一屆 Python Deep Dive 中 Chris 兄的筆記和影片介紹:

2 Likes