一、錯誤處理
高級語言都內置了一套“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
指定不同的級別就會輸出不同的信息
======================================
學藝不精、未完待續