程式扎記: [ The python tutorial ] 8. Errors and Exceptions

標籤

2012年1月16日 星期一

[ The python tutorial ] 8. Errors and Exceptions

翻譯自 這裡 
Errors and Exceptions : 
error 有兩種 syntax errors 與 exceptions, 底下我們就來談談這兩種 errors. 

Syntax Errors : 
語法錯誤簡單來說就是你的 script 給 Python 解析時, 它無法辨識你的語法 : 
>>> while True print 'Hello world'
File "", line 1, in ?
while True print 'Hello world'
^
SyntaxError: invalid syntax

Exceptions : 
還有一些 error 是發生在執行時期, 運算時產生的 exception. 這類的錯誤是可以透過一些機制補救處理的. 常見如下 : 
>>> 10 * (1/0)
Traceback (most recent call last):
File "", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
>>> 4 + spam*3
Traceback (most recent call last):
File "", line 1, in ?
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
File "", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects

常見標準的 built-in Exception 可以在 這裡 找到相關說明. 

Handling Exceptions : 
有些時候你可能希望在這些 Exceptions 發生時進行處理, 例如底下程式碼會在 Console 提供使用者輸入字串, 接著透過函式 int() 進行轉換. 如果你輸入的不是個合法字串, 則會發生 ValueError exception, 或者你直接按下 Ctrl + C (通常是在 Windows 下.) 則會發生 KeyboardInterrupt exception : 
 

上面有使用到 try 關鍵字, 用法如下說明 : 
* First, the try clause (the statement(s) between the try and except keywords) is executed.
* If no exception occurs, the except clause is skipped and execution of the try statement is finished.
* If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then if its type matches the exception named after the except keyword, the except clause is executed, and then execution continues after the try statement.
* If an exception occurs which does not match the exception named in the except clause, it is passed on to outer try statements; if no handler is found, it is anunhandled exception and execution stops with a message as shown above.

一個 try 的 statement 可以搭配多個 exception 的 handle, 甚至在同一個 handle 可以有多個 Exception 種類 : 
... except (RuntimeError, TypeError, NameError):
... pass

如果你希望有一個預設的 handle (即當 Exception 發生時, 所有設定的 Exception 類別都沒比對到時, 則執行預設 handle), 那就在 except 關鍵字後不用給任何 Exception 種類. 如下範例如果 Exception 發生時, 既不是 IOError 也不是 ValueError 時, 則執行最後一個 except clause : 
  1. import sys  
  2.   
  3. try:  
  4.     f = open('myfile.txt')  
  5.     s = f.readline()  
  6.     i = int(s.strip())  
  7. except IOError as (errno, strerror):  
  8.     print "I/O error({0}): {1}".format(errno, strerror)  
  9. except ValueError:  
  10.     print "Could not convert data to an integer."  
  11. except:  
  12.     print "Unexpected error:", sys.exc_info()[0]  
  13.     raise  
try ... except statement 還有一個 optional 的 else clause. 當你的 try clause 沒有發生任何 Exception 時, 該 else clause 就會被執行 : 
- countLine.py :
  1. import sys  
  2. for arg in sys.argv[1:]:  
  3.     try:  
  4.         f = open(arg, 'r')  
  5.     except IOError:  
  6.         print('\t[Error] cannot open {0}!'.format(arg))  
  7.     else:  
  8.         print('\t[Info] {0} has {1} lines...'.format(arg, len(f.readlines())))  
  9.         f.close()  

你也可以自己 raise Exception 並且傳入參數. 所有傳入的參數會被存放在 instance.args. 通常標準的 Exception 會定義函式 __str__() 將這些參數顯示出來. 下面是一個簡單範例 : 
 

Exception 的捕抓是 Recursive, 如果你在 try clause 中呼叫一個函式, 而該函式產生 Exception 的話且沒有 try clause 的話, 則外面的 try clause 可以捕捉 : 
 

Raising Exceptions : 
透過 raise 語法可以讓你強迫觸發 except clause : 
>>> raise NameError('HiThere')
Traceback (most recent call last):
File "", line 1, in
NameError: HiThere

另外如果你已經進入 exception clause, 但是你可能不想處理當前的 Exception, 則你可以在該 exception clause 在呼叫一次 raise 以重新拋出該 Exception 給更外部的 try clause : 
 

User-defined Exceptions : 
程式人員可以透過繼承類別 Exception 來撰寫自己的例外類別 (see Classes for more about Python classes
 

通常在實際應用中, 每個 Module 會重新定義自己的 Exception/Error base 類別 (繼承自 Exception 類別), 接著特定的 Error/Exception 再繼承該類別 : 
  1. class Error(Exception):  
  2.     """Base class for exceptions in this module."""  
  3.     pass  
  4.   
  5. class InputError(Error):  
  6.     """Exception raised for errors in the input.  
  7.   
  8.     Attributes:  
  9.         expr -- input expression in which the error occurred  
  10.         msg  -- explanation of the error  
  11.     """  
  12.   
  13.     def __init__(self, expr, msg):  
  14.         self.expr = expr  
  15.         self.msg = msg  
  16.   
  17. class TransitionError(Error):  
  18.     """Raised when an operation attempts a state transition that's not  
  19.     allowed.  
  20.   
  21.     Attributes:  
  22.         prev -- state at beginning of transition  
  23.         next -- attempted new state  
  24.         msg  -- explanation of why the specific transition is not allowed  
  25.     """  
  26.   
  27.     def __init__(self, prev, next, msg):  
  28.         self.prev = prev  
  29.         self.next = next  
  30.         self.msg = msg  
另外如果是標準的 Exception 類別, 你會發現它們都是以 'Error' 結尾. 建議如果你定義自己的 Exception 類別可以遵循標準走. 

Defining Clean-up Actions : 
try 用法還有另一個 optional clause (finally). 確保當不論如何這個 clause 一定會被執行到, 主要是作為 Clean-up 的功用存在, 範例如下 : 
 

底下是官網對於 finally clause 的說明 : 
finally clause is always executed before leaving the try statement, whether an exception has occurred or not. When an exception has occurred in the try clause and has not been handled by an except clause (or it has occurred in a except or else clause), it is re-raised after the finally clause has been executed. The finallyclause is also executed “on the way out” when any other clause of the try statement is left via a breakcontinue or return statement. In real world applications, the finally clause is useful for releasing external resources (such as files or network connections), regardless of whether the use of the resource was successful.

由下面的範例可以知道, 只要是離開 try clause, finally clause 就一定會被執行到 : 
 

Predefined Clean-up Actions : 
其實在 Python 的某些類別也提供一些簡潔的方法讓你做 Clean-up 的動作 (也就是不論成功或失敗都會執行!). 考慮代碼如下 : 
  1. for line in open("myfile.txt"):  
  2.     print line  
上述代碼的問題在於如果你在 for loop 中發生 exception 使得你無法優雅的關閉檔案 handle, 你可以藉由 with 語法確保你所開啟的 file object 不論成功失敗, 都一定會被"處理". 用法如下 : 
  1. with open("myfile.txt") as f:  
  2.     for line in f:  
  3.         print line  
Supplement : 
[Python 學習筆記] 起步走 : 陳述句 (try、raise 陳述句) 
[Python 學習筆記] 進階議題 : 例外 (使用 with as)

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!