這個(gè)問題是如何在一些場(chǎng)景下使用斷言表達(dá)式,通常會(huì)有人誤用它,所以我決定寫一篇文章來說明何時(shí)使用斷言,什么時(shí)候不用。
為那些還不清楚它的人,Python的assert是用來檢查一個(gè)條件,如果它為真,就不做任何事。如果它為假,則會(huì)拋出AssertError并且包含錯(cuò)誤信息。例如:
py> x = 23py> assert x > 0, "x is not zero or negative"py> assert x%2 == 0, "x is not an even number"Traceback (most recent call last):File "", line 1, inAssertionError: x is not an even number
很多人用assert作為一個(gè)很快和容易的方法來在參數(shù)錯(cuò)誤的時(shí)候拋出異常。但這樣做是錯(cuò)的,非常錯(cuò)誤,有兩個(gè)原因。首先AssertError不是在測(cè)試參數(shù)時(shí)應(yīng)該拋出的錯(cuò)誤。你不應(yīng)該像這樣寫代碼:
if not isinstance(x, int):raise AssertionError("not an int")
你應(yīng)該拋出TypeError的錯(cuò)誤,assert會(huì)拋出錯(cuò)誤的異常。
但是,更危險(xiǎn)的是,有一個(gè)關(guān)于assert的困擾:它可以被編譯好然后從來不執(zhí)行,如果你用 –O 或 –oo 選項(xiàng)運(yùn)行Python,結(jié)果不保證assert表達(dá)式會(huì)運(yùn)行到。當(dāng)適當(dāng)?shù)氖褂胊ssert時(shí),這是未來,但是當(dāng)assert不恰當(dāng)?shù)氖褂脮r(shí),它會(huì)讓代碼用-O執(zhí)行時(shí)出錯(cuò)。
那什么時(shí)候應(yīng)該使用assert?沒有特定的規(guī)則,斷言應(yīng)該用于:
防御型的編程 運(yùn)行時(shí)檢查程序邏輯 檢查約定 程序常量 檢查文檔(在測(cè)試代碼的時(shí)候使用斷言也是可接受的,是一種很方便的單元測(cè)試方法,你接受這些測(cè)試在用-O標(biāo)志運(yùn)行時(shí)不會(huì)做任何事。我有時(shí)在代碼里使用assert False來標(biāo)記沒有寫完的代碼分支,我希望這些代碼運(yùn)行失敗。盡管拋出NotImplementedError可能會(huì)更好。)
關(guān)于斷言的意見有很多,因?yàn)樗艽_保代碼的正確性。如果你確定代碼是正確的,那么就沒有用斷言的必要了,因?yàn)樗麄儚膩聿粫?huì)運(yùn)行失敗,你可以直接移除這些斷言。如果你確定檢查會(huì)失敗,那么如果你不用斷言,代碼就會(huì)通過編譯并忽略你的檢查。
在以上兩種情況下會(huì)很有意思,當(dāng)你比較肯定代碼但是不是絕對(duì)肯定時(shí)。可能你會(huì)錯(cuò)過一些非常古怪的情況。在這個(gè)情況下,額外的運(yùn)行時(shí)檢查能幫你確保任何錯(cuò)誤都會(huì)盡早地被捕捉到。
另一個(gè)好的使用斷言的方式是檢查程序的不變量。一個(gè)不變量是一些你需要依賴它為真的情況,除非一個(gè)bug導(dǎo)致它為假。如果有bug,最好能夠盡早發(fā)現(xiàn),所以我們?yōu)樗M(jìn)行一個(gè)測(cè)試,但是又不想減慢代碼運(yùn)行速度。所以就用斷言,因?yàn)樗茉陂_發(fā)時(shí)打開,在產(chǎn)品階段關(guān)閉。
一個(gè)非變量的例子可能是,如果你的函數(shù)希望在它開始時(shí)有數(shù)據(jù)庫的連接,并且承諾在它返回的時(shí)候仍然保持連接,這就是函數(shù)的不變量:
新聞熱點(diǎn)
疑難解答
圖片精選