Python如何合理使用assert(新手必讀)

2020-07-16 10:05:01
講完了 assert 的基本語法之後,本節通過一些實際應用的例子,給大家演示一下 assert 在 Python 中的用法,並明確 assert 的使用場景。

第一個例子,假設 C 語言中文網想做 VIP 促銷活動,準備進行打折,現需要寫一個 apply_discount() 函數,要求是,向該函數傳入原來的價格和折扣力度,該函數返回打折後的價格。

apply_discount() 大致應該寫成如下這樣:
#price 為原價,discount 為折扣力度
def apply_discount(price, discount):
    updated_price = price * (1 - discount)
    assert 0 <= updated_price <= price, '折扣價應在 0 和原價之間'
    return updated_price
可以看到,在計算新價格的後面,新增了一個 assert 語句,用來檢查折後價格,這裡要求新折扣價格必須大於等於 0、小於等於原來的價格,否則就丟擲異常。

我們可以試著輸入幾組數,來驗證一下這個功能:
print(apply_discount(100,0.2))
print(apply_discount(100,1.1))
執行結果為:

80.0
Traceback (most recent call last):
  File "C:UsersmengmaDesktopdemo.py", line 7, in <module>
    print(apply_discount(100,1.1))
  File "C:UsersmengmaDesktopdemo.py", line 4, in apply_discount
    assert 0 <= updated_price <= price, '折扣價應在 0 和原價之間'
AssertionError: 折扣價應在 0 和原價之間

可以看到,當 discount 是 0.2 時,輸出 80 沒有問題,但是當 discount 為 1.1 時,程式便丟擲下面 AssertionError 異常。

這樣一來,如果開發人員修改相關的程式碼,或者是加入新的功能,導致 discount 數值異常時,只要執行程式就很容易能發現問題,這也從側面印證了前面多講的,assert 的加入可以有效預防程式漏洞,提高程式的健壯性。

另外,在實際工作中,assert 還有一些很常見的用法,例如:
def func(input):
    assert isinstance(input, list), '輸入內容必須是列表'
    # 下面的操作都是基於前提:input 必須是 list
    if len(input) == 1:
        ...
    elif len(input) == 2:
        ...
    else:
        ...
上面程式碼中,func() 函數中的所有操作都基於輸入必須是列表這個前提。所以很有必要在開頭加一句 assert 的檢查,防止程式出錯。

以上給大家介紹了 2 個有關 assert 的使用場景,很多讀者可能覺得,assert 的作用和 if 語句非常接近,那麼他們之間是否可以相互替代呢?

要注意,前面講過,assert 的檢查是可以被關閉的,比如在命令列模式下執行 Python 程式時,加入 -O 選項就可以使程式中的 assert 失效。一旦 assert 失效,其包含的語句也就不會被執行。

還是拿 C 語言中文網使用者來說,只有 VIP 使用者才可以閱讀 VIP 文章,我們可以設計如下這個函數來模式判斷使用者身份的功能:
def login_user_identity(user_id):
    #憑藉使用者 id 判斷該使用者是否為 VIP 使用者
    assert user_is_Vip(user_id) "使用者必須是VIP使用者,才能閱讀VIP文章"
    read()
此程式碼從程式碼功能角度上看,並沒有問題,但在實際場景中,基本上沒人會這麼寫,因為一旦 assert 失效,則就造成任何使用者都可以閱讀 VIP 文章,這顯然是不合理的。

所以正確的做法是,使用 if 條件語句替代 assert 語句進行相關的檢查,並合理丟擲異常:
def login_user_identity(user_id):
    #憑藉使用者 id 判斷該使用者是否為 VIP 使用者
    if not user_is_Vip(user_id):
        raise Exception("使用者必須是VIP使用者,才能閱讀VIP文章")
    read()
總之,不能濫用 assert,很多情況下,程式中出現的不同情況都是意料之中的,需要用不同的方案去處理,有時用條件語句進行判斷更為合適,而對於程式中可能出現的一些異常,要記得用 try except 語句處理(後續章節會做詳細介紹)。