《python學習手冊》第34章 異常對象
基於字符串的異常
python在2.6之前可以使用字符串來定義異常,並且是通過對象標識符來匹配的(即通過is 而不是==)
myexc = "My excetion string" try: raise myexc except myexc: print(‘caught‘)
基於類的異常
字符串定義的異常非常簡單,但是並不容易維護。使用類定義的異常通過超類關系進行匹配,只要except列舉出來的異常的類或者任何超類名,引發的異常都會匹配到。此外,類的異常還支持異常狀態信息,可以讓異常參與繼承層次。
類異常的例子
class General(Exception):passclass Special1(General):pass class Special2(General):pass def raise0(): raise General() def raise1(): raise Special1() def raise2(): raise Special2() for fun in (raise0,raise1,raise2): try: fun() except General: import sys print(‘caught‘,sys.exc_info()[0])
運行的結果如下
caught <class‘__main__.General‘> caught <class ‘__main__.Special1‘> caught <class ‘__main__.Special2‘>
將excep的部分化為下面的內容,結果一樣,sys.exc_info將在下一章講到。
except General as x: print(‘caught:‘,x.__class__)
類異常的另一個例子
假如我們維護了一個mathlib.py的庫,原本定義了兩個異常Divzero和Oflow,
class Divzero(Exception): passclass Oflow(Exception): pass def func(): raise Divzero()
當別人使用我們的庫的時候我們可以進行異常處理:
import mathlib try: mathlib.func() except (mathlib.Divzero,mathlib.Oflow): ‘‘‘do what you want to do ‘‘‘
但是,當我們維護我們的庫的時候新加入一個異常Uflow的時候,別人必須修改他們的代碼,這樣在大型程序當中非常的不好。所以我們嘗試把我們庫中的代碼寫成下面的形式:
class NumErr(Exception):pass class Divzero(NumErr): pass class Oflow(NumErr): pass ‘‘‘其余的異常‘‘‘ def func(): raise Divzero()
別人引用的時候只需要寫成下面的形式即可:
import mathlib try: mathlib.func() except mathlib.NumErr: ‘‘‘do what you want to do ‘‘‘
無論我們增加多少個異常的類,別人的代碼都不需要進行修改。
內置Exception類
-BaseException類:異常的頂級根類,不可以被用戶定義的類直接繼承(應當使用Exception)。它提供了子類所繼承的默認的打印和狀態保持行為。
-Exception類:與應用相關的異常的頂層根超類,是BaseExcption的一個直接子類,並且是所有其他內置異常的超類,除了系統退出事件類以外(SystemExit、KeyboardInterrupt和GeneratorExit)。
In [2]: Exception.__bases__ Out[2]: (BaseException,)
In [3]: SystemExit.__bases__ Out[3]: (BaseException,)
-ArithmeticeError 所有數值錯誤的超類
In [4]: ArithmeticError.__bases__ Out[4]: (Exception,)
-OverflowError 識別特定的數值錯誤的子類
In [5]: OverflowError.__bases__ Out[5]: (ArithmeticError,)
從上面的代碼可以看出,python中的異常總是這樣的進行繼承的
默認打印和狀態
python內置異常提供默認的打印方法:傳遞給這些類的任何構造函數參數都會保存在實例的args元祖屬性中,並且當打印該實例的時候自動顯示。這就說明了為什麽傳遞給內置異常類的參數會出現在出錯消息中。
輸入:
raise IndexError
輸出:
Traceback (most recent call last): File "D:\application\eclipse\workspace\yichang\c3\t6.py", line 1, in <module> raise IndexError IndexError
輸入:
raise IndexError(‘nihao‘)
輸出:
Traceback (most recent call last): File "D:\application\eclipse\workspace\yichang\c3\t6.py", line 1, in <module> raise IndexError(‘nihao‘) IndexError: nihao
輸入:
i = IndexError(‘nihao‘) print(i.args)
輸出:
(‘nihao‘,)
同樣,我們自己定義的類也是如此,因為他們繼承了內置超類中存在的構造很熟和顯示方法
輸入:
class MyErr(Exception):pass try: raise MyErr(‘nihao‘) except MyErr as x: print(x,x.args)
輸出:
nihao (‘nihao‘,)
輸入:
class MyErr(Exception):pass try: raise MyErr(‘nihao‘,‘wohao‘,‘dajiahao‘) except MyErr as x: print(x,x.args)
輸出:
(‘nihao‘, ‘wohao‘, ‘dajiahao‘) (‘nihao‘, ‘wohao‘, ‘dajiahao‘)
為什麽輸出x和x.args是一樣的?因為,這是由於__str__來決定的,直接輸出了str(args)。
定制我們自己的打印顯示:
其實,主要是修改我們定制的類中的__str__和__repr__方法,而__str__又是主要的。
下面我們為我們自己定義的類當中重定義__str__方法:
class MyErr(Exception): def __str__(self): return ‘this is MYErr Exception‘ try: raise MyErr(‘nihao‘,‘wohao‘,‘dajiahao‘) except MyErr as x: print(x)
輸出: this is MYErr Exception
改造構造方法
class FormatError(Exception): def __init__(self,line,file): self.line = line self.file = file try: raise FormatError(2,‘nihao‘) except FormatError as x: print(x.line,x.file) print(x.args[0],x.args[1])
通過改造構造方法,可以體統更多的細節,但是args還是可以使用的,輸出結果如下:
2 nihao
2 nihao
定義一些方法,在處理器內部執行
class FormatError(Exception): logfile = r‘log.txt‘ def __init__(self,line,file): self.line = line self.file = file def logger(self): log = open(self.logfile,‘a‘) print(‘error at line:‘,self.line,‘file:‘,self.file,file=log) try: raise FormatError(11,‘t7.txt‘) except FormatError as x: x.logger()
該異常定義了出錯的時候存入特定文件夾的功能,當捕獲異常的時候,執行logger方法
執行後在log.txt中有如下語句: error at line: 11 file: t7.txt
總結:這一章我們其實是明確了,異常主要是通過類來實現的,在try語句中,捕捉其超類就會捕捉這個類,以及類樹中超類下的所有子類。
《python學習手冊》第34章 異常對象