1. 程式人生 > >Python中何時使用斷言 assert

Python中何時使用斷言 assert

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

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

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

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

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

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

  • 防禦性的程式設計
  • 執行時對程式邏輯的檢測
  • 合約性檢查(比如前置條件,後置條件)
  • 程式中的常量
  • 檢查文件

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

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

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

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

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

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

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

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

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

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

假設你有一系列的if...elif程式碼塊,你預先知道變數期望的值:

假設這段程式碼現在完全正確。但它會一直正確嗎?需求變更,程式碼變更。如果需求變為允許target = w,並關聯到run_w_code,那將會發生什麼情況?如果我們變更了設定target的程式碼,但是忘記了改變這個程式碼塊,它就會錯誤地呼叫run_z_code(),錯誤就會發生。對於這段程式碼最好的方法就是編寫一些防禦性的檢查,這樣它的執行,即使在變更以後,要麼正確,要麼馬上失敗。

在程式碼開始添加註釋是個好的開端,但是人們都不太喜歡讀和更新這些註釋,這些註釋會很快變得過時。但對於斷言,我們可以同時對這塊程式碼編寫文件,如果這些斷言被違反了,會直接引起一個簡單而又直接的失敗。

這裡的斷言同時用於防禦性程式設計和檢查文件。我認為這是最優的解決方案:

這誘使開發者去不理程式碼,移除像value ==c這類不必要的測試,以及RuntimeError的“死程式碼”。另外,當"unexpected error"錯誤發生時這個訊息將非常窘迫,確實會發生。

合約式設計是斷言另一個用得好的地方。在合約式設計中,我們認為函式與其他呼叫者遵循合約,例如像這樣的情況:

“如果你傳給我一個非空字串,我保證返回轉換成大寫的首字母。”

如果合約被破壞了,不管是被函式本身還是呼叫者,這都會產生缺陷。我們說這個函式需要有前置條件(對期望的引數的限制)和後置條件(對返回結果的約束)。因此這個函式可能是這樣的:

合約式設計的目的是,在一個正確的程式裡,所有的前置條件和後置條件都將得到處理。這是斷言的經典應用,自(這個想法持續)我們釋出無缺陷的程式並且將其放入產品,程式將是正確的並且我們可以放心地移除檢查。

這裡是我建議不使用斷言的情況:

*不要用於測試使用者提供的資料,或者那些需要在所有情況下需要改變檢查的地方

*不要用於檢查你認為在通常使用中可能失敗的地方。斷言用於非常特別的失敗條件。你的使用者絕不看到一個AssertionError,如果看到了,那就是個必須修復的缺陷。

*特別地不要因為斷言只是比一個明確的測試加一個觸發異常矮小而使用它。斷言不是懶惰的程式碼編寫者的捷徑。

*不要將斷言用於公共函式庫輸入引數的檢查,因為你不能控制呼叫者,並且不能保證它不破壞函式的合約。

*不要將斷言用於你期望修改的任何錯誤。換句話,你沒有任何理由在產品程式碼捕獲一個AssertionError異常。

*不要太多使用斷言,它們使程式碼變得晦澀難懂。

相關推薦

Python何時使用斷言 assert

使用斷言的最佳時機偶爾會被提起,通常是因為有人誤用,因此我覺得有必要寫一篇文章來闡述一下什麼時候應該用斷言,為什麼應該用,什麼時候不該用。 對那些沒有意識到用斷言的最佳時機的人來說,Python的斷言就是檢測一個條件,如果條件為真,它什麼都不做;反之它觸發一個帶可選錯誤資訊的AssertionError

python斷言

# python中的斷言方法舉例 a = 2 assert(a > 1) print("斷言成功,程式繼續向下執行") b = 2 assert(b >= 3), "b小於3" print("斷言失敗,程式報錯") # AssertionError: b小於3 斷言和異常的區別: 斷言是用

Java斷言assert的用法

Java陷阱之assert關鍵字   一、概述         在C和C++語言中都有assert關鍵,表示斷言。       在Java中,同樣也有assert關鍵字,表示斷言,用法和含義都差不多。

pythonassert斷言的用法

  本文轉載自  python中assert斷言的用法 >>> assert 1 == 0 Traceback (most recent call last):  File "<stdin>", line 1, in &l

python的分支和迴圈:for 迴圈,while迴圈,三元操作符,斷言assert關鍵字,rang()函式總結

1.python中的條件語句 例:score=int(input('請輸入一個分數'))        if 100>=score>=90:              

Python斷言assert的使用

   assert的語法格式:assert expression    它的等價語句為: if not expression: raise AssertionError 1、assert

Python的單元測試模組Unittest快速入門 unittest單元測試框架總結 Python單元測試unittest Python3 unittest斷言詳解 Python3 unittest單元測試 Python HTMLTestRunner 學習

前言 為什麼需要單元測試? 如果沒有單元測試,我們會遇到這種情況:已有的健康執行的程式碼在經過改動之後,我們無法得知改動之後是否引入了Bug。如果有單元測試的話,只要單元測試全部通過,我們就可以保證沒有Bug被引入。因此,單元測試是保證軟體工程質量的一個很重要的方面。 Python中的單元測試 Pyt

python assert的使用

assert : 斷言 為什麼使用assert 程式設計師斷定這個程式執行之後或者之前會有這樣的結果,如果不是,那就扔出一個錯誤。 語法: assert 表示式 [, 引數] 引數是一個字串,用於丟擲錯誤同時顯示 作用是判斷表示式是否成立(為真),如果不成立,丟擲As

Python 單元測試,assert斷言。單元測試案例,unittest.TestCase

  demo.py(assert斷言): # coding:utf-8 def divide(num1, num2): """除法""" assert isinstance(num1, int) # 斷言。 如果為真,繼續向下執行;如果為假,丟擲Assertio

Python 斷言 assert 的用法

assert 後邊接的表示式的返回值必須是布林值 assert expression, "對錯誤的描述資訊" 如果expression表示式返回的是True, 程式正常執行, 如果expression表示式返回的是False, 則丟擲 AssertionError, 如果需要加入異常的描述資

[python ] 斷言assert的使用

python 中的assert 可以簡化程式碼,讓python看起來如此簡單、優雅 一般我們做判斷,並丟擲異常,實現是: def raise_example(n): if not n > 5: raise Exception('num is

python執行cmd的方式

ble open blog cli return 窗口 images about 定向 目前我使用到的python中執行cmd的方式有三種: 1. 使用os.system("cmd") 這是最簡單的一種方法,特點是執行的時候程序會打出cmd在Linux上執行的信息。使用

JUnit的斷言 Assert

窗口 存儲 客戶端 pre 繼續 條件 測試 and 運行 何為 斷言: 斷言不僅僅是 一個報錯函數,它也是一個宏,並且作用並非“報錯”。 assert()的用法像是一種“契約式編程”

Python正則表達式(re模塊)的使用

python中正則表達式Python中正則表達式(re模塊)的使用1、正則表達式的概述(1)概述:正則表達式是一些由字符和特殊符號組成的字符串,他們描述了模式的重復或者表示多個字符,正則表達式能按照某種模式匹配一系列有相似特征的字符串。正則表達式是一種小型的、高度的專業化的編程語言,(2)Python語言中的

Python如何使用最小二乘法

python 技術 如何 模型 平面 之所以說”使用”而不是”實現”,是因為python的相關類庫已經幫我們實現了具體算法,而我們只要學會使用就可以了。隨著對技術的逐漸掌握及積累,當類庫中的算法已經無法滿足自身需求的時候,我們也可以嘗試通過自己的方式實現各種算法。 言

python關於編碼,json格式的中文輸出顯示

pri 整體 pytho src repr 接口 ensure 輸出 unicode 但我們用requests請求一個返回json的接口時候, 語法是 result=requests.post(url,data).content print type(result),re

Python的列表、元祖、字典

value pop val 什麽 刪除 append 更新 位置 增刪改 一、列表 一組有序項目的集合。可變的數據類型【可進行增刪改查】 列表是以方括號“[]”包圍的數據集合,不同成員以“,”分隔。 列表中能夠包括不論什麽數據類型,也可包括還有一個列表 列表可通過序號訪

Pythonsort()和sorted()的區別

-s 可變對象 傳遞 內置函數 ict pan 16px nbsp lin 1、sort()是可變對象(字典)的方法,無參數,無返回值, sort()會改變可變對象,因此無需返回值。例如: list: 1 >>> a = [4,3,7,8] 2 >

pythondir(),__dict__

區別 art 內存地址 code class article 參考 ict div dir()是python的一個函數, dir()函數如果接受的參數是一個類,則返回這個類所有的類變量和方法 dir()函數如果接收的參數是一個類的實例,則返回這個實例所有的實例變量,對應的類

Python: 淺淡Python的屬性(property)

-h format 有意思 _for hook 類添加屬性 eas style turn 起源:項目過程中需要研究youtube_dl這個開源組件,翻閱其中對類的使用,對比c#及Delphi中實現,感覺Python屬性機制挺有意思。區別與高級編程語言之單一入口,在類之屬性這