轉載自 這裡
前言 :
except 後若不接上任何例外型態,則表示捕捉所有例外,這包括了所有的系統例外,有時這並不是你想要的行為. 例如,下面這個程式,無法透過 KeyboardInterrup t 來中斷迴圈 :
再看 try、raise :
由於 except 捕捉所有的例外,所以上例無法離開迴圈. 你可以改為以下的方式 :
在 Python 3 中,
Exception 是 BaseException 的子類別,可以捕捉除了系統例外以外的所有例外. 上例可以藉由 KeyboardInterrupt 中斷迴圈. 在 Python 3 中,可以在 except 捕捉到例外後,將例外物件指定給變數. 例如 :
Output:
在更進階的例外追蹤需求中,可以使用 sys.exc_info() 方法取得一個 Tuple 物件,該 Tuple 物件中包括了 例外的類型、例外訊息 以及 traceback 物件 :
Output:
trackback 物件代表了呼叫堆疊中每一個層次的追蹤,可以使用 tb_next 取得更深一層的呼叫堆疊. 例如 :
- test1.py :
執行結果 :
tb_frame 代表了該層追蹤的所有物件資訊,f_code 可以取得該層的程式碼資訊,例如 co_name 可取得函式或模組名稱,而 co_filename 則表示該程式碼所在的檔案.
再來看看 raise 的使用,正如在 try 陳述句 中看到的,你可以在 raise 後接上字串或例外類別名稱,現在已不鼓勵 raise 字串實例。實際上,raise 之後可以接上例外類別名稱、例外實例或不接上任何東西. 當你在 raise 後接上例外類別時,實際上會以該類別建立實例再丟出,也就是下面兩行程式碼的作用是相同的 :
如果在
except 中使用 raise 而不接上任何物件,則表示將 except 比對到的例外實例再度丟出. 例如 :
Output:
如果必要的話,你還可以在 except 中 raise 例外時,附上自己的例外到 except 所比對到的例外實例. 例如 :
- test2.py :
執行結果 :
raise from 語法,會將 from 後接上的例外實例,設定給被 raise 的例外實例之 __cause__ . 例如 :
- test3.py :
執行結果 :
實際上,如果你在 except 中 raise 某個例外,則原 except 所比對到的例外,無論有無使用 raise from,都會自動設定給 __context__ . 例如 :
- test4.py :
執行結果 :
前言 :
except 後若不接上任何例外型態,則表示捕捉所有例外,這包括了所有的系統例外,有時這並不是你想要的行為. 例如,下面這個程式,無法透過 KeyboardInterrup t 來中斷迴圈 :
- while True:
- try:
- print('Run it....')
- except:
- print('exception happened...')
由於 except 捕捉所有的例外,所以上例無法離開迴圈. 你可以改為以下的方式 :
- while True:
- try:
- print('Run it....')
- except Exception:
- print('exception happened...')
- try:
- raise IndexError('11')
- except IndexError as e:
- print(type(e), str(e))
在更進階的例外追蹤需求中,可以使用 sys.exc_info() 方法取得一個 Tuple 物件,該 Tuple 物件中包括了 例外的類型、例外訊息 以及 traceback 物件 :
- import sys
- try:
- raise 'Error'
- except:
- a, b, c = sys.exc_info()
- print(a)
- print(b)
- print(c)
trackback 物件代表了呼叫堆疊中每一個層次的追蹤,可以使用 tb_next 取得更深一層的呼叫堆疊. 例如 :
- test1.py :
- import sys
- def test():
- raise EOFError
- try:
- test()
- except:
- type, message, traceback = sys.exc_info()
- while traceback:
- print('--------------')
- print('type=',type)
- print('message=', message)
- print('function or module? ', traceback.tb_frame.f_code.co_name)
- print('file? ', traceback.tb_frame.f_code.co_filename)
- traceback = traceback.tb_next
tb_frame 代表了該層追蹤的所有物件資訊,f_code 可以取得該層的程式碼資訊,例如 co_name 可取得函式或模組名稱,而 co_filename 則表示該程式碼所在的檔案.
再來看看 raise 的使用,正如在 try 陳述句 中看到的,你可以在 raise 後接上字串或例外類別名稱,現在已不鼓勵 raise 字串實例。實際上,raise 之後可以接上例外類別名稱、例外實例或不接上任何東西. 當你在 raise 後接上例外類別時,實際上會以該類別建立實例再丟出,也就是下面兩行程式碼的作用是相同的 :
- raise EOFError
- raise EOFError()
- try:
- raise EOFError
- except EOFError:
- print('got it')
- raise
如果必要的話,你還可以在 except 中 raise 例外時,附上自己的例外到 except 所比對到的例外實例. 例如 :
- test2.py :
- try:
- raise EOFError
- except EOFError as e:
- print('got it')
- raise IndexError from e
raise from 語法,會將 from 後接上的例外實例,設定給被 raise 的例外實例之 __cause__ . 例如 :
- test3.py :
- try:
- try:
- raise EOFError('XD')
- except EOFError as e:
- print('Except(EOFError): ', e.args)
- raise IndexError('Orz') from e
- except IndexError as e:
- print('Except(IndexError): ', e.args)
- print('\tArgs from cause: ', e.__cause__.args)
實際上,如果你在 except 中 raise 某個例外,則原 except 所比對到的例外,無論有無使用 raise from,都會自動設定給 __context__ . 例如 :
- test4.py :
- try:
- try:
- raise EOFError('XD')
- except EOFError as e:
- print('Except(EOFError): Args=', e.args)
- raise IndexError('Orz') from e
- except IndexError as e:
- print('Except(IndexError): Args=', e.args)
- print('\te.__cause__.args=', e.__cause__.args)
- print('\te.__context__.args=', e.__context__.args)
This message was edited 24 times. Last update was at 30/04/2017 18:57:34