使用 Python 断言语句进行有效调试

身為一名程式設計師,無論你使用哪種語言編寫程式碼,除錯都是一項至關重要的技能。本文將教你如何在 Python 中利用斷言語句,有效率地進行除錯工作。

在專案開發過程中,你可能會定義多個模組,包含函式、類別等。實作上若有疏失,可能會導致錯誤或出現非預期的結果。斷言語句正可以幫助你偵測並修正這類錯誤。

本教學將深入探討 `assert` 語句的語法,並透過程式碼範例,讓你了解其在實務上的應用。此外,我們也會說明何謂斷言錯誤,以及如何運用它來排除開發期間的程式碼錯誤。

讓我們開始吧!

如何在 Python 中使用 `assert` 語句

首先,我們將學習 `assert` 語句的語法,接著實際操作一些範例。

`assert` 語句的語法

在 Python 中,`assert` 語句的語法如下:

assert expression, message

其中:

  • expression 是一個有效的 Python 運算式,可以評估變數值的條件、變數的真偽、函式的回傳值等。
  • 如果 expression 的計算結果為 True,`assert` 語句不會拋出錯誤,也不會返回任何值,代表程式運作正常。
  • 如果 expression 的計算結果為 False,將會觸發 `AssertionError` 異常。
  • message 是一個可選的字串,當 `AssertionError` 異常觸發時,它會在回溯訊息中顯示。

接下來,我們將透過幾個範例,說明 `assert` 語句如何幫助我們撰寫更清晰且無錯誤的程式碼。

你可以在這個 GitHub Gist 中找到本教學所使用的程式碼範例。

Python 的 `assert` 語句範例

假設你的程式碼中定義了一個折扣變數,你希望它的值永遠小於或等於 max_discount。為了確保折扣變數不會意外地被設定成不合理的值,你可以使用斷言來驗證 discount <= max_discount 這個條件是否成立。

>>> max_discount = 50
>>> discount = 20
>>> assert discount <= max_discount

在這個例子中,discount (20) 小於 max_discount (50),所以 `assert` 語句不會拋出任何錯誤。

斷言錯誤異常

如果折扣變數被設定成大於 max_discount 的值,就會觸發 `AssertionError` 異常。

>>> discount = 75
>>> assert discount <= max_discount
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

我們知道 `assert` 語句允許我們設定一個可選的訊息字串。

我們可以透過訊息字串,提供更詳盡的診斷資訊。以下程式碼中,我們在 `assert` 語句中加入了一個 Python f-string,其中包含了 discountmax_discount 的值。

>>> assert discount <= max_discount, f"discount should be at most {max_discount}; got discount = {discount}"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: discount should be at most 50; got discount = 75

如上所示,`AssertionError` 異常現在包含了 discountmax_discount 變數的值,讓開發者更容易判斷錯誤發生的原因。

使用 `assert` 偵錯和測試 Python 函式

在定義函式時,有時可能會不小心引入錯誤(邏輯錯誤),導致函式無法如預期般運作。

讓我們舉個例子。假設某堂課進行了一項測驗,學生可以選擇是否挑戰額外的加分題。只要學生挑戰了加分題,就可以在測驗中獲得額外 10 分的加分。 😄

考慮以下的 get_final_score 函式:

  • 它接收目前的成績、加分和一個布林值。
  • 如果學生挑戰了加分題 (布林值為 True),他們將比目前的成績多獲得 10 分。
  • 函式接著返回最終成績。
def get_final_score(score,bonus):
    if bonus:
        score += 10
    return score

讓我們對這個函式進行幾次呼叫。當分數為 34 和 40,且 bonus 分別設定為 TrueFalse 時,最終成績分別為 44 和 40。

print(get_final_score(34,True))
# 44
print(get_final_score(40,False))
# 40

然而,測驗的最高分是 50 分。因此,如果學生獲得 49 分,並且挑戰了加分題,函式 get_final_score 會很高興地計算出最終成績為 59。

print(get_final_score(49,True))
# 59

技術上來說,這是可行的。但是,假設學生分數不能超過測驗的最大可能分數。 🙂

因此,讓我們初始化一個 max_score 變數,並將函式返回的分數記錄在 final_score 變數中。

接著,我們添加一個斷言來檢查 final_score 是否小於等於 max_score

def get_final_score(score,bonus):
    if bonus:
        score += 10
    return score

final_score = get_final_score(47,True)
max_score = 50

assert final_score <= max_score

現在,我們收到呼叫 get_final_score(47,True) 時所觸發的 `AssertionError` 異常:

Traceback (most recent call last):
  File "main.py", line 17, in <module>
    assert final_score <= max_score
AssertionError

現在,我們為 Python `assert` 語句添加一個描述性的 f-string:

assert final_score <= max_score,f"final_score should be at most {max_score}; got {final_score}"
Traceback (most recent call last):
  File "main.py", line 17, in <module>
    assert final_score <= max_score,f"final_score should be at most {max_score}; got {final_score}"
AssertionError: final_score should be at most 50; got 57

修改函式

讓我們回頭修改 get_final_score 函式的定義,以修正意外行為:

  • get_final_score 函式現在也接受 max_score 作為參數。
  • 我們檢查 bonus 是否為 True。如果是 True,則將 10 分加到 score 變數。
  • 然後,我們檢查 score 是否大於 max_score。如果是,我們返回 max_score
  • 否則,我們返回 score

我們現在已經確保最終分數永遠小於或等於 max_score

def get_final_score(score,bonus,max_score):
    if bonus:
        score += 10
    if score > max_score:
        return max_score
    return score

作為一個快速練習,請撰寫一些斷言,以確認函式現在是否如預期般運作。

關於 `AssertionError` 異常的注意事項

雖然當運算式計算結果為 False 時會發生 AssertionError 異常,但我們應該記住不要將此類錯誤作為例外處理。也就是說,我們不應該這樣做:

try:
    <doing this>
except AssertionError:
    <do this>

在前面關於 get_final_score 的範例中,我們使用斷言來檢查 final_score 是否小於 max_score。然後,我們修改了函式定義,使得不再有斷言錯誤。

這正是斷言的用途所在。它們是程式碼的健全性檢查,有助於撰寫更清晰的程式碼。另一方面,例外處理是在執行期間預測和處理意外錯誤,通常包含無效的輸入類型和值。

總而言之,您應該使用 Python 的 `assert` 語句進行有效除錯,而不是將 `AssertionError` 當作例外處理。

結論

本教學幫助您了解如何在 Python 中使用 `assert` 語句。以下是您所學內容的總結:

  • Python 斷言語句 (assert) 採用斷言運算式的形式,用於檢查運算式是否為真。如果其計算結果不是 True,則會引發 AssertionError 異常。
  • 您還可以使用語法 assert expression, message 的斷言。每當發生 AssertionError 異常時,將會印出訊息字串。
  • 您應該記住不要實施例外處理來處理斷言錯誤,並將斷言用作有用的除錯工具,以檢查程式碼的完整性。

身為開發人員,斷言可以協助您進行除錯。為了確保專案中的所有獨立元件(模組)如預期般運作,您可以學習如何使用 Python 撰寫單元測試。

接下來,你可以參考一些適合初學者的 Python 專案列表。