歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Python 使用斷言的最佳時機

使用斷言的最佳時機偶爾會被提起,通常是因為有人誤用,因此我覺得有必要寫一篇文章來闡述一下什麼時候應該用斷言,為什麼應該用,什麼時候不該用。

對那些沒有意識到用斷言的最佳時機的人來說,Python的斷言就是檢測一個條件,如果條件為真,它什麼都不做;反之它觸發一個帶可選錯誤信息的AssertionError。如下例所示:

py> x = 23
py> 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 "<stdin>", line 1, in <module>
AssertionError: x is not an even number

很多人將斷言作為當傳遞了錯誤的參數值時的一種快速而簡便的觸發異常的方式。但實際上這是錯誤的,而且是非常危險的錯誤,原因有兩點。首先,AssertionError通常是在測試函數參數時給出的錯誤。你不會像下面這樣編碼:

if not isinstance(x, int):
    raise AssertionError("not and int")

你應該用TypeError來替代,“斷言”解決了錯誤的異常類型。

但是對斷言來說更危險也更糾結的是:如果你執行Python時使用了-O或-OO優化標識,這能夠通過編譯卻從來不會被執行,實際上就是說並不能保證斷言會被執行。當恰當地使用了斷言,這非常好的,但當不恰當地使用了斷言,在使用-O標識執行時它將導致代碼被徹底中斷。

那麼我們什麼時候應該使用斷言呢?如果沒有特別的目的,斷言應該用於如下情況:

  • 防御性的編程
  • 運行時對程序邏輯的檢測
  • 合約性檢查(比如前置條件,後置條件)
  • 程序中的常量
  • 檢查文檔

(斷言也可以用於代碼測試,用作一個做事毛手毛腳的開發人員的單元測試,只要能你接受當使用-O標志時這個測試什麼都不做。我有時也會在代碼中用"assert Fasle"來對還沒有實現的分支作標記,當然我希望他們失敗。如果稍微更細節一些,或許觸發NotImplementedError是更好的選擇)

因為程序員是對於代碼正確性表現出的信心不同,因此對於什麼時候使用斷言的意見各不相同。如果你確信代碼是正確的,那麼斷言沒有任何意義,因為它們從不會失敗,因此你可以放心地移除它們。如果你確信它們會失敗(例如對用戶輸入的數據的檢測),你不敢用斷言,這樣編譯就能通過,但你跳過了你的檢查。

在以上兩種情況之間的情況就顯得特別有趣了,那就是當你相信代碼是正確的,但又不是特別確定的時候。或許你忘記了一些奇怪的邊角情況(因為我們都是人),在這種情況下,額外的運行時檢查將幫助你盡可能早地捕獲錯誤,而不是寫了一大堆代碼之後。

(這就是為什麼使用斷言的時機會不同。因為我們對代碼正確性的信息不同,對於一個人有用的斷言,對於另一個人來說卻是無用的運行時測試。)

另一個斷言用得好的地方就是檢查程序中的不變量。一個不變量是一些你能相信為真的條件,除非一個缺陷導致它變成假。如果有一個缺陷,越早發現越好,因此我們需要對其進行測試,但我們不想因為這些測試而影響代碼執行速度。因此采用斷言,它能在開發時生效而在產品中失效。

一個關於不變量的例子可能是這樣的情況。如果你的函數在開始的時候期望一個打開的數據庫連接,並且在函數返回後該數據庫連接依然是打開的,這是一個函數的不變量:

def some_function(arg):
    assert not DB.closed()
    ... # code goes here
    assert not DB.closed()
    return result

斷言也是一個很好的檢查點注釋。為了替代如下注釋:

#當我們執行到這裡,我們知道n>2

你可以確保在運行時用以下斷言:

assert n > 2

斷言也是一種防御性的編程形式。你不是在防范當前代碼發生錯誤,而防范由於以後的代碼變更發生錯誤。理想情況下,單元測試應該直到這個作用,但是讓我們面對這樣一個現實:即使存在單元測試,他們在通常情況下也不是很完備。內建的機器人可能沒有工作,但數周以來也沒有人注意到它,或者人們在提交代碼之前忘記了執行測試。內部檢查將是防止錯誤滲入的另一道防線,尤其對於那些悄悄地失敗,但會引起代碼功能錯誤並返回錯誤結果的情況有效。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2013-12/93629p2.htm

Copyright © Linux教程網 All Rights Reserved