Learning Python(4)--錯誤處理

在程序運行過程中,總會遇到各種各樣的錯誤。

有的錯誤是程序編寫有問題造成的,比如本來應該輸出整數結果輸出了字符串,這種錯誤我們通常稱之爲bug,bug是必須修復的。

有的錯誤是用戶輸入造成的,比如讓用戶輸入email地址,結果得到一個空字符串,這種錯誤可以通過檢查用戶輸入來做相應的處理。

還有一類錯誤是完全無法在程序運行過程中預測的,比如寫入文件的時候,磁盤滿了,寫不進去了,或者從網絡抓取數據,網絡突然斷掉了。這類錯誤也稱爲異常,在程序中通常是必須處理的,否則,程序會因爲各種問題終止並退出。

Python內置了一套異常處理機制,來幫助我們進行錯誤處理。

此外,我們也需要跟蹤程序的執行,查看變量的值是否正確,這個過程稱爲調試。Python的pdb可以讓我們以單步方式執行代碼。

最後,編寫測試也很重要。有了良好的測試,就可以在程序修改後反覆運行,確保程序輸出符合我們編寫的測試。

錯誤處理機制

try

高級語言一般都內置一套try....except....finally的錯誤處理機制。

try的一個例子:

try:
    print ('try...')
    r=10/0
    print ('result:%s'%r)
except ZeroDivisionError as e:
    print ('except:',e)
finally:
    print('finally...')
print ('END')

如果我們認爲某些代碼可能出錯,就可以用try來運行這段代碼,如果代碼出錯,則後續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,即except語句塊處,執行完後,如果有finally語句塊,則執行finally語句塊,至此,執行完畢。
如果沒有錯誤發生,except語句塊不會執行,但是finally有的話,會被執行。(可以沒有finally語句)。然後,程序繼續按照流程往下走。

若有多種類型的錯誤,可以使用多個except來捕獲不同類型的錯誤。

try:
    print('try...')
    r = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

另外可以在except後面加一個else,當沒有錯誤發生時,會自動執行else語句。

Key point:

  • ZeroDivisionError是一種可以被捕獲的錯誤。所有被捕獲的錯誤其實也是class,所有的錯誤類型都繼承自BaseException,所以在使用except時需要注意的是,它不但捕獲該類型的錯誤,還把其子類也“一網打盡”。比如:
try:
    foo()
except ValueError as e:
    print('ValueError')
except UnicodeError as e:
    print('UnicodeError')

       第二個except永遠也捕獲不到UnicodeError,因爲UnicodeError是ValueError的子類,如果有,也被第一個except給捕獲了。

  • python3中except的語法爲except ... as .. :。但是python2中語法爲except ... , ..。as用逗號代替。
  • 使用try...except捕獲錯誤還有一個巨大的好處,就是可以跨越多層調用,比如函數main()調用foo()foo()調用bar(),結果bar()出錯了,這時,只要main()捕獲到了,就可以處理:
def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        print('Error:', e)
    finally:
        print('finally...')

調用堆棧

若沒有try...except語句捕獲錯誤,當程序遇到錯誤時,沒有將錯誤一直想上拋,最後被python解釋器捕獲,打印出調用的堆棧後,再打印一個錯誤信息,然後程序退出

記錄錯誤

如果不捕獲錯誤,自然可以讓Python解釋器來打印出錯誤堆棧,但程序也被結束了。既然我們能捕獲錯誤,就可以把錯誤堆棧打印出來,然後分析錯誤原因,同時,讓程序繼續執行下去。
logging模塊可以非常容易的記錄錯誤信息:

import logging

def foo(s):
    return 10 / int(s)

def bar(s):
    return foo(s) * 2

def main():
    try:
        bar('0')
    except Exception as e:
        logging.exception(e)

main()
print('END')

同樣是出錯,但程序打印完錯誤信息後會繼續執行,並正常退出。
通過配置,logging還可以把錯誤記錄到日誌文件裏,方便事後排查。

拋出錯誤

FIXME:raise

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章