>>> try:
... print('try...')
... r = 10 / 0
... print('result:', r)
... except ZeroDivisionError as e:
... print('except:', e)
... finally:
... print('finally...')
... print('END')
...
try...
except: division by zero
finally...
END
當我們認為某些代碼可能會出錯時,就可以用try來運作這段代碼,如果執行出錯,則後續代碼不會繼續執行,而是直接跳轉至錯誤處理代碼,即except語句塊,執行完except後,如果有finally語句塊,則執行finally語句塊,至此,執行完畢。
finally語句塊無論是否執行except,都會被執行的。
同時定義多個except
... r = 10 / int('a')
... except ValueError as e: --異常1
... print('ValueError:', e)
... except ZeroDivisionError as e: --異常2
... else: --無異常時執行else
... print('no error')
ValueError: invalid literal for int() withbase 10: 'a'
跨越多層調用
使用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...')
>>> main()
Error: division by zero
隻要在合适的層次去捕獲錯誤就可以了。
[root@daidai python]# cat err.py
#!/bin/bash/python
# -*- coding:utf-8 -*-
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
bar('0')
main()
[root@daidai python]# python err.py
Traceback (most recent call last):
File "err.py", line 13, in <module>
main()
File "err.py", line 11, in main
File "err.py", line 8, in bar
File "err.py", line 5, in foo
ZeroDivisionError: division by zero --最後便是錯誤的根源
捕捉錯誤,把錯誤堆棧記錄,讓程式繼續運作。
Python内置的logging子產品可以非常容易地記錄錯誤資訊。
[root@daidai python]# cat err_logging.py
#!/usr/bin/python
import logging
try:
bar('0')
except Exception as e:
logging.exception(e)
print('END')
[root@daidai python]# python err_logging.py
ERROR:root:division by zero
File "err_logging.py", line 14, in main
bar('0')
File "err_logging.py", line 10, in bar
File "err_logging.py", line 7, in foo
ZeroDivisionError: division by zero
盡量使用python内置的錯誤類型。
錯誤是class,捕獲一個錯誤就是捕獲到該class的一個執行個體。
定義一個錯誤class,選擇好繼承關系。
>>> class FooError(ValueError):
... pass
... n = int(s)
... if n == 0:
... raise FooError('invalid value: %s' % s)
... return 10 / n
>>> foo('0')
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in foo
__main__.FooError: invalid value: 0 --自己定義的錯誤
另一種錯誤處理方式——錯誤上抛
... raise ValueError('invalid value: %s' %s) --python内置錯誤
... return 10 /n
>>> def bar():
... foo('0')
... except ValueError as e:
... print('ValueError')
... raise --raise語句如果不帶參數,就會把目前錯誤原樣抛出。
>>> bar()
ValueError
File "<stdin>", line 3, in bar
ValueError: invalid value: 0
其實這種錯誤處理方式不但沒病,而且相當常見。捕獲錯誤目的隻是記錄一下,便于後續追蹤。但是,由于目前函數不知道應該怎麼處理該錯誤,是以,最恰當的方式是繼續往上抛,讓頂層調用者去處理。好比一個員工處理不了一個問題時,就把問題抛給他的老闆,如果他的老闆也處理不了,就一直往上抛,最終會抛給CEO去處理。
在except中raise一個Error,還可以把一種類型的錯誤轉化成另一種類型
... 10 / 0
... except ZeroDivisionError:
... raise ValueError('input error')
File "<stdin>", line 2, in <module>
During handling of the above exception,another exception occurred:
File "<stdin>", line 4, in <module>
ValueError: input error