Python day 9(5) 錯誤處理

來源:互聯網
上載者:User

標籤:不同   one   back   tps   pre   ...   end   使用者   跟蹤   

一:錯誤、調試和測試

1 程式運行中的錯誤:

   a 程式編寫有問題造成的,這種錯誤我們通常稱之為bug,bug是必須修複的。

   b 使用者輸入造成的,可以通過檢查使用者輸入來做相應的處理。

   c 還有一類錯誤是完全無法在程式運行過程中預測的,比如寫入檔案的時候,磁碟滿了,寫不進去了,或者從網路抓取資料,網路突然斷掉了。這類錯誤也稱為異常,在程式中通常是必須處理的,否則,程式會因為各種問題終止並退出。

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

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

二:錯誤處理(用try......except......finally)

1 (用try......except......finally來捕獲錯誤)

1 try:2     print(‘try...‘)3     r = 10 / 04     print(‘result:‘, r)5 except ZeroDivisionError as e:6     print(‘except:‘, e)7 finally:8     print(‘finally...‘)9 print(‘END‘)

     a       當我們認為某些代碼可能會出錯時,就可以用try來運行這段代碼,如果執行出錯,則後續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,即except語句塊,執行完except後,如果有finally語句塊,則執行finally語句塊,至此,執行完畢。

    b        錯誤可能有很多種類,如果發生了不同類型的錯誤,應該由不同的except語句塊處理。沒錯,可以有多個except來捕獲不同類型的錯誤:

 int()函數可能會拋出ValueError,所以我們用一個except捕獲ValueError,用另一個except捕獲ZeroDivisionError

此外,如果沒有錯誤發生,可以在except語句塊後面加一個else,當沒有錯誤發生時,會自動執行else語句:

 1 try: 2     print(‘try...‘) 3     r = 10 / int(‘2‘) 4     print(‘result:‘, r) 5 except ValueError as e: 6     print(‘ValueError:‘, e) 7 except ZeroDivisionError as e: 8     print(‘ZeroDivisionError:‘, e) 9 else:10     print(‘no error!‘)11 finally:12     print(‘finally...‘)13 print(‘END‘)

 

    c       Python的錯誤其實也是class,所有的錯誤類型都繼承自BaseException,所以在使用except時需要注意的是,它不但捕獲該類型的錯誤,還把其子類也“一網打盡”。比如:

1 try:2     foo()3 except ValueError as e:4     print(‘ValueError‘)5 except UnicodeError as e:6     print(‘UnicodeError‘)

 

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

Python所有的錯誤都是從BaseException類派生的,常見的錯誤類型和繼承關係看這裡:

https://docs.python.org/3/library/exceptions.html#exception-hierarchy

     d        使用try...except捕獲錯誤還有一個巨大的好處,就是可以跨越多層調用,比如函數main()調用foo()foo()調用bar(),結果bar()出錯了,這時,只要main()捕獲到了,就可以處理:

 1 def foo(s): 2     return 10 / int(s) 3  4 def bar(s): 5     return foo(s) * 2 6  7 def main(): 8     try: 9         bar(‘0‘)10     except Exception as e:11         print(‘Error:‘, e)12     finally:13         print(‘finally...‘)

 也就是說,不需要在每個可能出錯的地方去捕獲錯誤,只要在合適的層次去捕獲錯誤就可以了。這樣一來,就大大減少了寫try...except...finally的麻煩。

 

2  調用棧(不用try......except......finally來捕獲)

如果錯誤沒有被捕獲,它就會一直往上拋,最後被Python解譯器捕獲,列印一個錯誤資訊,然後程式退出。

 1 def foo(s): 2     return 10 / int(s) 3  4 def bar(s): 5     return foo(s) * 2 6  7 def main(): 8     bar(‘0‘) 9 10 main()

 結果如下:

 1 $ python3 err.py 2 Traceback (most recent call last): 3   File "err.py", line 11, in <module> 4     main() 5   File "err.py", line 9, in main 6     bar(‘0‘) 7   File "err.py", line 6, in bar 8     return foo(s) * 2 9   File "err.py", line 3, in foo10     return 10 / int(s)11 ZeroDivisionError: division by zero

 不過要自己分析錯誤的調用棧資訊,定位錯誤的位置。

3  記錄錯誤

如果不捕獲錯誤,自然可以讓Python解譯器來列印出錯誤堆棧,但程式也被結束了。既然我們能捕獲錯誤,就可以把錯誤堆棧列印出來,然後分析錯誤原因,同時,讓程式繼續執行下去。

Python內建的logging模組可以非常容易地記錄錯誤資訊:

 1 import logging 2  3 def foo(s): 4     return 10 / int(s) 5  6 def bar(s): 7     return foo(s) * 2 8  9 def main():10     try:11         bar(‘0‘)12     except Exception as e:13         logging.exception(e)14 15 main()16 print(‘END‘)

 

同樣是出錯,但程式列印完錯誤資訊後會繼續執行,並正常退出

 1 $ python3 err_logging.py 2 ERROR:root:division by zero 3 Traceback (most recent call last): 4   File "err_logging.py", line 13, in main 5     bar(‘0‘) 6   File "err_logging.py", line 9, in bar 7     return foo(s) * 2 8   File "err_logging.py", line 6, in foo 9     return 10 / int(s)10 ZeroDivisionError: division by zero11 END

 

通過配置,logging還可以把錯誤記錄到記錄檔裡,方便事後排查。

4  拋出錯誤

 

因為錯誤是class,捕獲一個錯誤就是捕獲到該class的一個執行個體。因此,錯誤並不是憑空產生的,而是有意建立並拋出的。Python的內建函數會拋出很多類型的錯誤,我們自己編寫的函數也可以拋出錯誤。

如果要拋出錯誤,首先根據需要,可以定義一個錯誤的class,選擇好繼承關係,然後,用raise語句拋出一個錯誤的執行個體

 1 # err_raise.py 2 class FooError(ValueError): 3     pass 4  5 def foo(s): 6     n = int(s) 7     if n==0: 8         raise FooError(‘invalid value: %s‘ % s) 9     return 10 / n10 11 foo(‘0‘)

 

執行,可以最後跟蹤到我們自己定義的錯誤

1 $ python3 err_raise.py 2 Traceback (most recent call last):3   File "err_throw.py", line 11, in <module>4     foo(‘0‘)5   File "err_throw.py", line 8, in foo6     raise FooError(‘invalid value: %s‘ % s)7 __main__.FooError: invalid value: 0

只有在必要的時候才定義我們自己的錯誤類型。如果可以選擇Python已有的內建的錯誤類型(比如ValueErrorTypeError),盡量使用Python內建的錯誤類型。

 

Python day 9(5) 錯誤處理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.