環境:python 3.10_amd64 + Win10
1.doctest用法:
doctest是python自帶的測試模凷, 可根據文檔字符串內的語句進行簡單測試.
----代碼案例: 簡單測試----
import doctest # 導入根據文檔字符串執行測試的模凷
def average(values):
"""計算數值列表的平均值
>>> average([1,3,5,7]) # 函數調用
4.0 # 預期結果
"""
return sum(values)/len(values)
doctest.testmod() # testmod()自動執行文檔字符串內的語句
"""這是文檔字符串""", 這樣的格式除了用于描述多行字符串常量之外, 也可用于類/函數的分行註釋, 一般稱作文檔字符串(docstring). 進行自動測試函數功能時, 首先得導入doctest模凷; 其次在文檔字符串內, 使用>>>提示符, 模擬python shell的格式, 注意>>>後一定要空一格, 然後輸入函數調用語句, 再換行輸入預期結果; 最後調用doctest.testmod()函數進行測試.
文檔內允許多項測試語句, 如:
...
>>> average([1,3,5,7])
4.0
>>> average([1,2,5,2])
2.5
...
如果預期結果等于return的返回值, 則通過測試, shell或終端啥也不會會輸出, 如下圖:
PS C:\Users\34513> & C:/Users/34513/.../python.exe c:/Users/.../main.py
PS C:\Users\34513>
如果測試未通過(比如將上例的預期結果改爲2.0), 終端的輸出如下, 會指明具体行數的哪項測試未通過, 挺直白的:
**********************************************************************
File "C:\Users\34513\...\main.py", line 7, in __main__.average
Failed example:
average([1,3,5,7])
Expected:
2.0
Got:
4.0
**********************************************************************
1 items had failures:
1 of 1 in __main__.average
***Test Failed*** 1 failures.
1.1.報錯~~ValueError:... lacks blank after >>>: ...
ValueError: line 3 of the docstring for __main__.average lacks blank after >>>: ' >>>average([1,3,5,7])'
這个錯誤解釋的很直白, 就是文檔字符串中>>>後缺少了一个空格, 輸入時仔細點, 別漏了就是.
1.2.報錯~~AttributeError:
partially initialized module 'doctest' has no attribute 'testmod' (most likely due to a circular import)
大意是說, 部份初始化的模凷doctest沒有testmod屬性(可能是由于循環導入引起).導致這種錯誤的原因是因爲文件名與現有模凷名重復引起的(所以才叫循環/反復導入), import語句就近導入了一个不當命名的.py文件, 因此與現有模凷衝突.
本例中我是用doctest.py命名文件時觸發了這个錯誤, 只要重命名文件(比如tmp.py啊之類的無風險的名稱), 避免與現有模凷或python保留字重復即可.
2.try/except異常處理
2.1.try/except語法
對于可預知的程序錯誤, 使用try/except語句可以在錯誤發生時執行特定動作, 避免程序崩潰.
----代碼實例: 當發生除數爲0的計算錯誤時發出提示
print("輸入兩个數, 我來計算它們的商.")
print("按'q'退出程序.")
while True:
first_number = input("\nFirst number: ")
if first_number == 'q':
break
second_number = input("Second number: ")
if second_number == 'q':
break
try:
answer = float(first_number) / float(second_number)
except ZeroDivisionError:
print('0不能用作除數!')
else:
print(answer) # 在無異常時的行爲
----代碼實例: 讀取文件, 找不到文件時輸出錯誤信息:
def count_words(filename):
"""計算一个文本中包含的單詞數量"""
try:
with open(filename) as file_object:
text_open = file_object.read()
except FileNotFoundError:
message = '無法找到文件!\n請檢查路徑或創建文件:' + filename
print(message)
else:
words_list = text_open.split() # split()方法將文本以單詞分割, 返回列表
numbers = len(words_list) # 計算全文的詞數
return numbers
上面兩个例子說明了try/except的基本用法, 即預判可能發生的錯誤, 將python標準錯誤名寫在語句中, 並輸出友好的反饋信息.
2.2.多種異常的處理
1.針對不同的異常情況作不同處理(即執行不同的語句), 如:
try:
# 待測試語句凷
except IOError:
# 出現IO錯誤, 做點啥
except TypeError:
# 出現類型錯誤, 做點啥
這樣比較細緻地處理了多種情況, 比如進行報錯時也更明瞭.
2.將多種可能的異常列爲元組, 統一處理
try:
# 待測試語句凷
except (ValueError, TypeError, TypeError):
# 對于以上多種異常, 做點啥
這樣好像只是節省了代碼量, 處理太籠統了.
3.統一處理所有異常
在try/except中, 不指定任何異常, 就是不管發生啥, 都統一處理, 籠統的程度更甚, 如:
# ...
try:
print(x/y)
except:
print('出錯!')