使用 assert
May 4, 2022斷言(Assertion)指的是程式進行到某個時間點,斷定其必然是某種狀態,具體而言,也就是斷定該時間點上,某變數必然是某值,或某物件必具擁有何種特性值。
assert 陳述
在 Python 中要進行斷言測試,可以使用 assert
陳述句:
assert <test>, <message>
test
是狀態測試,而 message
是斷言失敗時所要呈現訊息。例如,在定義的 Account
類別裡,存款的時候不能提負數,提款的時候也不能是負數,呼叫 deposit
或 withdraw
時傳入的值必然是大於 0,這時可以使用斷言檢查:
class Account:
def __init__(self, number, name):
self.number = number
self.name = name
self.balance = 0
def deposit(self, amount):
assert amount > 0, '必須是大於 0 的正數'
self.balance += amount
def withdraw(self, amount):
assert amount > 0, '必須是大於 0 的正數'
if amount <= self.balance:
self.balance -= amount
else:
raise RuntimeError('balance not enough')
a = Account('E122', 'Justin')
a.deposit(-1) # AssertionError: 必須是大於 0 的正數
類似的,在一個 if
判斷中,如果 x
大於 0,就執行 if
區塊,否則 x
必須是等於 0,這時也可使用斷言測試:
if x > 0:
# do some
...
else:
assert x == 0, 'x 此時一定要是 0,不會是負數'
# do other
...
或者是物件某個方法執行過後,必然處於某個狀態,例如 Stack
的 pop
執行過後,長度必然是少 1:
class Stack:
def __init__(self):
self.idx = 0
self.data = []
def push(self, c):
length = len(self.data)
self.data.append(c)
assert (length + 1) == len(self.data)
def pop(self):
length = len(self.data)
ele = self.data.pop()
assert (length - 1) == len(self.data)
return ele
停用斷言
斷言是用來斷定程式某個時間點的狀態,最基本的原則是,斷言執行前後,不可以改變任何程式狀態,也就是不可以產生任何邊際效應。
這是因為斷言可以在最佳化時被省略,也就是最後編譯出來的程式碼,不會包括 assert
陳述句,這可以在使用 python
直譯器時,加上 -O
引數來達到,這時程式中 __debug__
會被設為 False
,也就不會包括或執行 assert
陳述句。例如:
print(__debug__)
assert False
上面這個程式,若執行 python
時加上 -O
引數,就不會引發 AssertionError
。由於 assert
有可能不會執行,因此,你的斷言相關程式碼,不得對程式狀態有任何改變。
因此,當你寫一個 assert
陳述時:
assert test, 'some message' # test 結果為 True 或 False
相當於在做以下的動作:
if __debug__:
if not test:
raise AssertionError('some message')