Python錯誤、除錯和測試
一、錯誤處理
高階語言都內建了一套“try…..except…..finally”錯誤處理機制。
①try機制
try:
r=12/0
print ('result:',r)
except ZeroDivisionEror,e: #e可用其他字元代替,表示一個變數,在這裡e=='inter division or modulo by zero'
print 'except:',e
finally:#finnally可有可無,無論程式碼是否有錯誤都會執行
print 'finally....'
print 'end'
上面程式碼在計算12/0時會產生一個除法運算錯誤:
except: integer division or modulo by zero
finally….
end
當發生錯誤時不再執行print ‘result:’,r
若沒有錯誤發生,except語句不會執行;另外錯誤會有不同種類,所以可以有多個不同的except語句;如果沒有錯誤發生,可以在except語句後加一個else語句,沒有錯誤發生就可以執行該語句。另:所有的錯誤型別都繼承自BaseException,所以可以用一個expect StandardError,e: 語句,省去用多個except語句去捕獲錯誤。
使用try….expect 可以跨越多層呼叫,呼叫函式,函式巢狀無論在哪一層出錯都可以捕獲到比如下例:
def foo(s)
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except StandardError, e:
print 'Error!'
finally:
print 'finally...'
main()
輸出:
Error integer division or modulo by zero
可見錯誤出現在foo()函式中,在函式呼叫中main()函式仍可以捕獲到
②呼叫堆疊
如果錯誤為被找到,則會列印錯誤資訊
def f1(s):
return 12/int(s)
def f2(s):
return f1(s)*2
def main():
f2('0')
main()
執行:結果如下
Traceback (most recent call last): File "F:/python 程式碼/錯誤處理.py", line 7, in <module> main() File "F:/python 程式碼/錯誤處理.py", line 6, in main f2('0') File "F:/python 程式碼/錯誤處理.py", line 4, in f2 return f1(s)*2 File "F:/python 程式碼/錯誤處理.py", line 2, in f1 return 12/int(s) ZeroDivisionError: integer division or modulo by zero
可以看出,出現錯誤的地方為:
File "F:/python 程式碼/錯誤處理.py", line 2, in f1
return 12/int(s)
③記錄錯誤
python內建的logging模組可以記錄錯誤,把錯誤堆疊打印出來,同時讓程式繼續執行下去。
import logging #先匯入
def f1(s):
return 12/int(s)
def f2(s):
return f1(s)*2
def main():
try:
f2('0')
except StandardError,e: #增加的步驟
logging.exception(e)
main()
print('End')
於上個程式碼相比匯入import,使用try…except。雖然同樣出錯,但列印完錯誤資訊後會繼續執行,並正常退出,執行程式碼如下:
ERROR:root:integer division or modulo by zero
Traceback (most recent call last):
File "F:/python 程式碼/錯誤處理.py", line 8, in main
f2('0')
File "F:/python 程式碼/錯誤處理.py", line 5, in f2
return f1(s)*2
File "F:/python 程式碼/錯誤處理.py", line 3, in f1
return 12/int(s)
ZeroDivisionError: integer division or modulo by zero
End
錯誤是一個class,例如python的內建函式:ValueError(),StandardError()…..或者我們自己定義一個錯誤類(必要的時候),但需要選擇好繼承關係例如:FooError(StandardError)…所以我們捕獲到的錯誤就是類的一個例項。
我們可以根據需要,選擇或定義一個錯誤類,用raise語句丟擲錯誤。
def f3(s):
n=int(s)
if n==0:
raise StandardError('invalid value: %s' % s)
return 12/0
f3('0')
執行如下:
Traceback (most recent call last):
File "F:/python 程式碼/錯誤處理.py", line 21, in <module>
f3('0')
File "F:/python 程式碼/錯誤處理.py", line 19, in f3
raise StandardError('invalid value: %s' % s)
StandardError: invalid value: 0
列印完錯誤資訊且程式繼續執行。
另一種非常常見的錯誤處理方式:
def foo1(s):
n = int(s)
return 10 / n
def bar1(s):
try:
return foo1(s) * 2
except StandardError, e:
print 'Error!'
raise
def main1():
bar1('0')
main1()
執行結果如下:
Error!
Traceback (most recent call last):
File "F:/python 程式碼/錯誤處理.py", line 30, in <module>
main1()
File "F:/python 程式碼/錯誤處理.py", line 28, in main1
bar1('0')
File "F:/python 程式碼/錯誤處理.py", line 22, in bar1
return foo1(s) * 2
File "F:/python 程式碼/錯誤處理.py", line 19, in foo1
return 10 / n
ZeroDivisionError: integer division or modulo by zero
可見,編輯器已經知道了有錯誤,而且又把錯誤通過raise丟擲便於管理者儘快找出錯誤原因!若無raise則只輸出“Error”!
二、除錯
logging
與assert判斷或print列印錯誤相比,logging不會丟擲錯誤
import logging
s='0'
n=int(s)
logging.info('n=%d' %n) #logging.info()可以輸出一段文字,且其需放在可能會出錯誤的語句之前
print 10/n
執行後只會輸出ZeroDivisionError,這跟logging制定記錄的錯誤資訊級別有關,有debug,info,warning,error等幾個級別,例如在import logging後匯入:
import logging
logging.basicConfig(level=logging.INFO)
會輸出
INFO:root:n = 0
Traceback (most recent call last):
File "err.py", line 8, in <module>
print 10 / n
ZeroDivisionError: integer division or modulo by zero
指定不同的級別就會輸出不同的資訊
======================================
學藝不精、未完待續