Python程式設計入門(7) (轉)

worldblog發表於2007-12-07
Python程式設計入門(7) (轉)[@more@]

第八章 錯誤與例外

到現在為止我們只是提到了錯誤資訊而沒有詳細討論,如果你執行了前面的例子可能已經看到了一些錯誤資訊。至少有兩種不同錯誤:句法錯和例外錯(exceptions)。

8.1 句法錯

 句法錯也稱為語法分析錯,是你在學習的時候最可能犯的錯誤。

>>> while 1 print 'Hello world' File "", line 1 while 1 print 'Hello world' ^ SyntaxError: invalid syntax


語法分析器重複出錯行,並用一個小‘箭頭’指向行內最早發現錯誤的位置。錯誤是由箭頭前面的記號引起的(至少是在這裡檢測到的)。在本例中,錯誤在關鍵字print處檢測到,因為它前面應該有一個冒號(“:”)。錯誤資訊中顯示了名和行號這樣如果錯誤發生在一個指令碼檔案中你就知道到哪裡去找。

8.2 例外

即使語句或句法沒有問題,在試圖執行的時候也可能發生錯誤。執行時檢測到的錯誤叫做例外,這種錯誤不一定必然是致命的:你很快就會學到如何在Python中處理例外。然而,多數例外不能被程式處理,這是會產生錯誤資訊,如:

>>> 10 * (1/0) Traceback (innermost last): File "", line 1 ZeroDivisionError: integer division or modulo >>> 4 + spam*3 Traceback (innermost last): File "", line 1 NameError: spam >>> '2' + 2 Traceback (innermost last): File "", line 1 TypeError: illegal argument type for built-in operation


錯誤資訊的最後一行顯示發生的情況。例外有不同的型別,型別作為錯誤資訊的一部分顯示:上例中錯誤的型別有ZeroDivisionError、NameError和TypeError。作為例外型別顯示的字串是發生的例外的內建名。這對於所有內建例外成立,但對自定義例外不一定成立(使用者最好能遵守這樣的約定)。標準例外名是內建的識別符號(不是保留關鍵字)。

此行的其餘部分是錯誤的細節,其解釋依賴於例外型別。錯誤資訊前面的部分以堆疊反跟蹤的形式顯示了發生錯誤的上下文環境。一般這包含了列出行的一個列出源程式行的堆疊反跟蹤;然而,它不會顯示從標準輸入讀進的行。

 庫參考手冊列出了內建例外和其含義。 

8.3 例外處理

 可以序來處理選定的例外。請看下面的例子,顯示一些浮點數的倒數:

>>> numbers = [0.3333, 2.5, 0, 10] >>> for x in numbers: ... print x, ... try: ... print 1.0 / x ... except ZeroDivisionError: ... print '*** has no inverse ***' ... 0.3333 3.00030003 2.5 0.4 0 *** has no inverse *** 10 0.1


try語句是這樣工作的:

  • 首先,執行try子句(在try和except之間的語句)。
  • 如果沒有發生例外,跳過except子句,try語句執行完畢。
  • 如果在try子句中發生了例外錯誤而且例外錯誤匹配except後指定的例外名,則跳過try 子句剩下的部分,except子句,然後繼續執行try語句後面的程式。
  • 如果在try子句中發生了例外錯誤但是例外錯誤不匹配except後指定的例外名,則此例外被傳給外層的try語句。如果沒有找到匹配的處理程式則此例外稱作是未處理例外,程式停止執行,顯示錯誤資訊。

try語句可以有多個except子句,為不同的例外指定不同處理。至多隻執行一個錯誤處理程式。錯誤處理程式只處理相應的try子句中發生的例外,如果同try語句中其它的錯誤處理程式中發生例外錯誤處理程式不會反應。一個except子句可以列出多個例外,寫在括號裡用逗號分開,例如:

... except (RuntimeError, TypeError, NameError): ... pass


最後一個except子句可以省略例外名,作為一個通配項。這種方法要謹慎使用,因為這可能會導致程式實際已出錯卻發現不了。

try ... except語句有一個可選的else子句,如有的話要放在所有except子句之後。else 的意思是沒有發生例外,我們可以把try子句中沒有發生例外時要做的事情放在這個子句裡。例如:

for arg in sys.argv[1:]: try: f = open(arg, 'r') except IOError: print '不能開啟', arg else: print arg, '有', len(f.readlines()), '行' f.close()


例外發生時可能伴有一個值,叫做例外的引數。引數是否存在及其型別依賴於例外的型別。對於有引數的例外,except在自居可以在例外名(或表)後指定一個變數用來接受例外的引數值,如:

>>> try: ... spam() ... except NameError, x: ... print 'name', x, 'undefined' ... name spam undefined


有引數的例外未處理時會在錯誤資訊的最後細節部分列出其引數值。 

例外處理程式不僅處理直接產生於try子句中的例外,也可以處理try子句中的(甚至是間接呼叫的函式)中的例外。如:

>>> def this_fails(): ... x = 1/0 ... >>> try: ... this_fails() ... except ZeroDivisionError, detail: ... print 'Handling run-time error:', detail ... Handling run-time error: integer division or modulo


8.4 產生例外

raise語句允許程式設計師強行產生指定的例外。例如:

>>> raise NameError, 'HiThere' Traceback (innermost last): File "", line 1 NameError: HiThere


raise語句的第一個引數指定要產生的例外的名字。可選的第二引數指定例外的引數。 

8.5 使用者自定義例外

程式中可以定義自己的例外,只要把一個字串賦給一個變數即可。例如:

>>> my_exc = 'my_exc' >>> try: ... raise my_exc, 2*2 ... except my_exc, val: ... print 'My exception occurred, value:', val ... My exception occurred, value: 4 >>> raise my_exc, 1 Traceback (innermost last): File "", line 1 my_exc: 1


許多標準模組用這種方法報告自己定義的函式中發生的錯誤。 

8.6 定義清理動作

  try語句還有另一個finally可選子句,可以用來規定不論出錯與否都要執行的動作。例如:

>>> try: ... raise KeyboardInterrupt ... finally: ... print 'Gooye, world!' ... Goodbye, world! Traceback (innermost last): File "", line 2 KeyboardInterrupt


finally子句不論try子句中是否發生例外都會執行。例外發生時,先執行finally子句然後重新提出該例外。當try語句用break或return語句退出時也將執行finally子句。

要注意的是,try語句有了except子句就不能有finally子句,有了finally子句就不能有except 子句,不能同時使用except子句和finally子句。需要的話可以巢狀。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989398/,如需轉載,請註明出處,否則將追究法律責任。

相關文章