2017年4月30日 星期日

[Python 學習筆記] 進階議題 : 例外 (再看 try、raise)

轉載自 這裡
前言 :
except 後若不接上任何例外型態,則表示捕捉所有例外,這包括了所有的系統例外,有時這並不是你想要的行為. 例如,下面這個程式,無法透過 KeyboardInterrup t 來中斷迴圈 :
  1. while True:  
  2.     try:  
  3.         print('Run it....')  
  4.     except:  
  5.          print('exception happened...')  
再看 try、raise :
由於 except 捕捉所有的例外,所以上例無法離開迴圈. 你可以改為以下的方式 :
  1. while True:  
  2.     try:  
  3.         print('Run it....')  
  4.     except Exception:  
  5.          print('exception happened...')  
在 Python 3 中,Exception 是 BaseException 的子類別,可以捕捉除了系統例外以外的所有例外. 上例可以藉由 KeyboardInterrupt 中斷迴圈. 在 Python 3 中,可以在 except 捕捉到例外後,將例外物件指定給變數. 例如 :
  1. try:  
  2.     raise IndexError('11')  
  3. except IndexError as e:  
  4.     print(type(e), str(e))  
Output:
11


在更進階的例外追蹤需求中,可以使用 sys.exc_info() 方法取得一個 Tuple 物件,該 Tuple 物件中包括了 例外的類型、例外訊息 以及 traceback 物件 :
  1. import sys  
  2.   
  3. try:  
  4.     raise 'Error'  
  5. except:  
  6.     a, b, c = sys.exc_info()  
  7.     print(a)  
  8.     print(b)  
  9.     print(c)  
Output:

exceptions must derive from BaseException


trackback 物件代表了呼叫堆疊中每一個層次的追蹤,可以使用 tb_next 取得更深一層的呼叫堆疊. 例如 :
- test1.py :
  1. import sys  
  2. def test():  
  3.     raise EOFError  
  4.   
  5. try:  
  6.     test()  
  7. except:  
  8.     type, message, traceback = sys.exc_info()  
  9.     while traceback:  
  10.         print('--------------')  
  11.         print('type=',type)  
  12.         print('message=', message)  
  13.         print('function or module? ', traceback.tb_frame.f_code.co_name)  
  14.         print('file? ', traceback.tb_frame.f_code.co_filename)  
  15.         traceback = traceback.tb_next  
執行結果 :
--------------
type=
message=
function or module?
file? ./a.py
--------------
type=
message=
function or module? test
file? ./a.py

tb_frame 代表了該層追蹤的所有物件資訊,f_code 可以取得該層的程式碼資訊,例如 co_name 可取得函式或模組名稱,而 co_filename 則表示該程式碼所在的檔案.

再來看看 raise 的使用,正如在 try 陳述句 中看到的,你可以在 raise 後接上字串或例外類別名稱,現在已不鼓勵 raise 字串實例。實際上,raise 之後可以接上例外類別名稱、例外實例或不接上任何東西. 當你在 raise 後接上例外類別時,實際上會以該類別建立實例再丟出,也就是下面兩行程式碼的作用是相同的 :
  1. raise EOFError  
  2. raise EOFError()  
如果在 except 中使用 raise 而不接上任何物件,則表示將 except 比對到的例外實例再度丟出. 例如 :
  1. try:  
  2.     raise EOFError  
  3. except EOFError:  
  4.     print('got it')  
  5.     raise  
Output:
got it
Traceback (most recent call last):
File "./a.py", line 3, in
raise EOFError
EOFError

如果必要的話,你還可以在 except 中 raise 例外時,附上自己的例外到 except 所比對到的例外實例. 例如 :
- test2.py :
  1. try:  
  2.     raise EOFError  
  3. except EOFError as e:  
  4.     print('got it')  
  5.     raise IndexError from e  
執行結果 :
got it
Traceback (most recent call last):
File "./a.py", line 3, in
raise EOFError
EOFError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "./a.py", line 6, in
raise IndexError from e
IndexError

raise from 語法,會將 from 後接上的例外實例,設定給被 raise 的例外實例之 __cause__ . 例如 :
- test3.py :
  1. try:  
  2.     try:  
  3.         raise EOFError('XD')  
  4.     except EOFError as e:  
  5.         print('Except(EOFError): ', e.args)  
  6.         raise IndexError('Orz') from e  
  7. except IndexError as e:  
  8.     print('Except(IndexError): ', e.args)  
  9.     print('\tArgs from cause: ', e.__cause__.args)  
執行結果 :
Except(EOFError): ('XD',)
Except(IndexError): ('Orz',)
Args from cause: ('XD',)

實際上,如果你在 except 中 raise 某個例外,則原 except 所比對到的例外,無論有無使用 raise from,都會自動設定給 __context__ . 例如 :
- test4.py :
  1. try:  
  2.     try:  
  3.         raise EOFError('XD')  
  4.     except EOFError as e:  
  5.         print('Except(EOFError): Args=', e.args)  
  6.         raise IndexError('Orz') from e  
  7. except IndexError as e:  
  8.     print('Except(IndexError): Args=', e.args)  
  9.     print('\te.__cause__.args=', e.__cause__.args)  
  10.     print('\te.__context__.args=', e.__context__.args)  
執行結果 :
Except(EOFError): Args= ('XD',)
Except(IndexError): Args= ('Orz',)
e.__cause__.args= ('XD',)
e.__context__.args= ('XD',)

This message was edited 24 times. Last update was at 30/04/2017 18:57:34

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...