引發例外狀況

已完成

現在您已充分了解追蹤及處理例外狀況,讓我們來引發例外狀況。

您可能已經了解撰寫程式碼時可能會導致錯誤狀況的情況。 在這些情況下,引發例外狀況很實用,這可讓其他程式碼了解問題是什麼。

引發例外狀況也有助於針對其他程式碼做出決策。 如先前所見,依據錯誤,程式碼可以做出明智的決策來解決、處理或忽略問題。

太空人每天將其用水量限制為大約 11 公升。 讓我們建立一個可依據太空人數目來計算若干天數之後會剩多少水量的函式:

def water_left(astronauts, water_left, days_left):
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    return f"Total water left after {days_left} days is: {total_water_left} liters"

試試看五位太空人、100 公升剩餘水量,以及兩天的時間:

water_left(5, 100, 2)
'Total water left after 2 days is: -10 liters'

這並不實用,因為不足的公升數應該會是錯誤。 然後,導覽系統可能會向太空人發出警示,指出在兩天內,每個人將沒有足夠的水。 若您是設計導覽系統程式的工程師,您可以在 water_left() 函式中引發例外狀況來警示錯誤狀況:

def water_left(astronauts, water_left, days_left):
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    if total_water_left < 0:
        raise RuntimeError(f"There is not enough water for {astronauts} astronauts after {days_left} days!")
    return f"Total water left after {days_left} days is: {total_water_left} liters"

現在再執行一次:

water_left(5, 100, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in water_left
RuntimeError: There is not enough water for 5 astronauts after 2 days!

在導覽系統中,發出警示訊號的程式碼現在可使用 RuntimeError 來警示:

try:
    water_left(5, 100, 2)
except RuntimeError as err:
    alert_navigation_system(err)

您也可以更新 water_left() 函式,以防止傳遞不支援的類型。 嘗試傳遞不是整數的引數,以檢查錯誤輸出:

water_left("3", "200", None)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in water_left
TypeError: can't multiply sequence by non-int of type 'NoneType'

在函式預期的內容中,來自 TypeError 的錯誤並不容易理解。 更新函式,使其使用 TypeError 但具有較容易理解的訊息:

def water_left(astronauts, water_left, days_left):
    for argument in [astronauts, water_left, days_left]:
        try:
            # If argument is an int, the following operation will work
            argument / 10
        except TypeError:
            # TypeError will be raised only if it isn't the right type 
            # Raise the same exception but with a better error message
            raise TypeError(f"All arguments must be of type int, but received: '{argument}'")
    daily_usage = astronauts * 11
    total_usage = daily_usage * days_left
    total_water_left = water_left - total_usage
    if total_water_left < 0:
        raise RuntimeError(f"There is not enough water for {astronauts} astronauts after {days_left} days!")
    return f"Total water left after {days_left} days is: {total_water_left} liters"

現在再試一次,以取得更容易理解的錯誤:

water_left("3", "200", None)
Traceback (most recent call last):
  File "<stdin>", line 5, in water_left
TypeError: unsupported operand type(s) for /: 'str' and 'int'

During handling of the preceding exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 9, in water_left
TypeError: All arguments must be of type int, but received: '3'