Python錯誤和異常小結


原文鏈接    http://blog.csdn.net/sinchb/article/details/8392827

     事先說明哦,這不是一篇關於Python異常的全面介紹的文章,這只是在學習Python異常后的一篇筆記式的記錄和小結性質的文章。什么?你還不知道什么是異常,額...

1.Python異常類

    Python是面向對象語言,所以程序拋出的異常也是類。常見的Python異常有以下幾個,大家只要大致掃一眼,有個映像,等到編程的時候,相信大家肯定會不只一次跟他們照面(除非你不用Python了)。

python標准異常

異常名稱

描述

   

BaseException

所有異常的基類

SystemExit

解釋器請求退出

KeyboardInterrupt

用戶中斷執行(通常是輸入^C)

Exception

常規錯誤的基類

StopIteration

迭代器沒有更多的值

GeneratorExit

生成器(generator)發生異常來通知退出

SystemExit

Python 解釋器請求退出

StandardError

所有的內建標准異常的基類

ArithmeticError

所有數值計算錯誤的基類

FloatingPointError

浮點計算錯誤

OverflowError

數值運算超出最大限制

ZeroDivisionError

除(或取模)零 (所有數據類型)

AssertionError

斷言語句失敗

AttributeError

對象沒有這個屬性

EOFError

沒有內建輸入,到達EOF 標記

EnvironmentError

操作系統錯誤的基類

IOError

輸入/輸出操作失敗

OSError

操作系統錯誤

WindowsError

系統調用失敗

ImportError

導入模塊/對象失敗

KeyboardInterrupt

用戶中斷執行(通常是輸入^C)

LookupError

無效數據查詢的基類

IndexError

序列中沒有沒有此索引(index)

KeyError

映射中沒有這個鍵

MemoryError

內存溢出錯誤(對於Python 解釋器不是致命的)

NameError

未聲明/初始化對象 (沒有屬性)

UnboundLocalError

訪問未初始化的本地變量

ReferenceError

弱引用(Weak reference)試圖訪問已經垃圾回收了的對象

RuntimeError

一般的運行時錯誤

NotImplementedError

尚未實現的方法

SyntaxError

Python 語法錯誤

IndentationError

縮進錯誤

TabError

Tab 和空格混用

SystemError

一般的解釋器系統錯誤

TypeError

對類型無效的操作

ValueError

傳入無效的參數

UnicodeError

Unicode 相關的錯誤

UnicodeDecodeError

Unicode 解碼時的錯誤

UnicodeEncodeError

Unicode 編碼時錯誤

UnicodeTranslateError

Unicode 轉換時錯誤

Warning

警告的基類

DeprecationWarning

關於被棄用的特征的警告

FutureWarning

關於構造將來語義會有改變的警告

OverflowWarning

舊的關於自動提升為長整型(long)的警告

PendingDeprecationWarning

關於特性將會被廢棄的警告

RuntimeWarning

可疑的運行時行為(runtime behavior)的警告

SyntaxWarning

可疑的語法的警告

UserWarning

用戶代碼生成的警告

 

異常

描述

NameError

嘗試訪問一個沒有申明的變量

ZeroDivisionError

除數為0

SyntaxError

語法錯誤

IndexError

索引超出序列范圍

KeyError

請求一個不存在的字典關鍵字

IOError

輸入輸出錯誤(比如你要讀的文件不存在)

AttributeError

嘗試訪問未知的對象屬性

ValueError

傳給函數的參數類型不正確,比如給int()函數傳入字符串形

2.捕獲異常

    Python完整的捕獲異常的語句有點像:

[html] view plaincopy

  1. try:  
  2.     try_suite  
  3. except Exception1,Exception2,...,Argument:  
  4.     exception_suite  
  5. ......   #other exception block  
  6. else:  
  7.     no_exceptions_detected_suite  
  8. finally:  
  9.     always_execute_suite  

    額...是不是很復雜?當然,當我們要捕獲異常的時候,並不是必須要按照上面那種格式完全寫下來,我們可以丟掉else語句,或者finally語句;甚至不要exception語句,而保留finally語句。額,暈了?好吧,下面,我們就來一一說明啦。

2.1.try...except...語句

    try_suite不消我說大家也知道,是我們需要進行捕獲異常的代碼。而except語句是關鍵,我們try捕獲了代碼段try_suite里的異常后,將交給except來處理。

    try...except語句最簡單的形式如下:

[python] view plaincopy

  1. try:  
  2.     try_suite  
  3. except:  
  4.     exception block  

    上面except子句不跟任何異常和異常參數,所以無論try捕獲了任何異常,都將交給except子句的exception block來處理。如果我們要處理特定的異常,比如說,我們只想處理除零異常,如果其他異常出現,就讓其拋出不做處理,該怎么辦呢?這個時候,我們就要給except子句傳入異常參數啦!那個ExceptionN就是我們要給except子句的異常類(請參考異常類那個表格),表示如果捕獲到這類異常,就交給這個except子句來處理。比如:

[python] view plaincopy

  1. try:  
  2.     try_suite  
  3. except Exception:  
  4.     exception block  

    舉個例子:

[python] view plaincopy

  1. >>> try:  
  2. ...     res = 2/0  
  3. ... except ZeroDivisionError:  
  4. ...     print "Error:Divisor must not be zero!"  
  5. ...   
  6. Error:Divisor must not be zero!  

    看,我們真的捕獲到了ZeroDivisionError異常!那如果我想捕獲並處理多個異常怎么辦呢?有兩種辦法,一種是給一個except子句傳入多個異常類參數,另外一種是寫多個except子句,每個子句都傳入你想要處理的異常類參數。甚至,這兩種用法可以混搭呢!下面我就來舉個例子。

[python] view plaincopy

  1. try:  
  2.     floatnum = float(raw_input("Please input a float:"))  
  3.     intnum = int(floatnum)  
  4.     print 100/intnum  
  5. except ZeroDivisionError:  
  6.     print "Error:you must input a float num which is large or equal then 1!"  
  7. except ValueError:  
  8.     print "Error:you must input a float num!"  
  9.   
  10. [root@Cherish tmp]# python test.py   
  11. Please input a float:fjia  
  12. Error:you must input a float num!  
  13. [root@Cherish tmp]# python test.py   
  14. Please input a float:0.9999  
  15. Error:you must input a float num which is large or equal then 1!  
  16. [root@Cherish tmp]# python test.py   
  17. Please input a float:25.091  
  18. 4  

    上面的例子大家一看都懂,就不再解釋了。只要大家明白,我們的except可以處理一種異常,多種異常,甚至所有異常就可以了。

    大家可能注意到了,我們還沒解釋except子句后面那個Argument是什么東西?別着急,聽我一一道來。這個Argument其實是一個異常類的實例(別告訴我你不知到什么是實例),包含了來自異常代碼的診斷信息。也就是說,如果你捕獲了一個異常,你就可以通過這個異常類的實例來獲取更多的關於這個異常的信息。例如:

[python] view plaincopy

  1. >>> try:  
  2. ...     1/0  
  3. ... except ZeroDivisionError,reason:  
  4. ...     pass  
  5. ...   
  6. >>> type(reason)  
  7. <type 'exceptions.ZeroDivisionError'>  
  8. >>> print reason  
  9. integer division or modulo by zero  
  10. >>> reason  
  11. ZeroDivisionError('integer division or modulo by zero',)  
  12. >>> reason.__class__  
  13. <type 'exceptions.ZeroDivisionError'>  
  14. >>> reason.__class__.__doc__  
  15. 'Second argument to a division or modulo operation was zero.'  
  16. >>> reason.__class__.__name__  
  17. 'ZeroDivisionError'  

    上面這個例子,我們捕獲了除零異常,但是什么都沒做。那個reason就是異常類ZeroDivisionError的實例,通過type就可以看出。

2.2try ... except...else語句

    現在我們來說說這個else語句。Python中有很多特殊的else用法,比如用於條件和循環。放到try語句中,其作用其實也差不多:就是當沒有檢測到異常的時候,則執行else語句。舉個例子大家可能更明白些:

[python] view plaincopy

  1. >>> import syslog  
  2. >>> try:  
  3. ...     f = open("/root/test.py")  
  4. ... except IOError,e:  
  5. ...     syslog.syslog(syslog.LOG_ERR,"%s"%e)  
  6. ... else:  
  7. ...     syslog.syslog(syslog.LOG_INFO,"no exception caught\n")  
  8. ...   
  9. >>> f.close()  

2.3 finally子句

    finally子句是無論是否檢測到異常,都會執行的一段代碼。我們可以丟掉except子句和else子句,單獨使用try...finally,也可以配合except等使用。

例如2.2的例子,如果出現其他異常,無法捕獲,程序異常退出,那么文件 f 就沒有被正常關閉。這不是我們所希望看到的結果,但是如果我們把f.close語句放到finally語句中,無論是否有異常,都會正常關閉這個文件,豈不是很 妙

[python] view plaincopy

  1. >>> import syslog  
  2. >>> try:  
  3. ...     f = open("/root/test.py")  
  4. ... except IOError,e:  
  5. ...     syslog.syslog(syslog.LOG_ERR,"%s"%e)  
  6. ... else:  
  7. ...     syslog.syslog(syslog.LOG_INFO,"no exception caught\n")  
  8. ... finally:   
  9. >>>     f.close()  

    大家看到了沒,我們上面那個例子竟然用到了try,except,else,finally這四個子句!:-),是不是很有趣?到現在,你就基本上已經學會了如何在Python中捕獲常規異常並處理之。

3.兩個特殊的處理異常的簡便方法

3.1斷言(assert)

    什么是斷言,先看語法:

[python] view plaincopy

  1. assert expression[,reason]  

    其中assert是斷言的關鍵字。執行該語句的時候,先判斷表達式expression,如果表達式為真,則什么都不做;如果表達式不為真,則拋出異常。reason跟我們之前談到的異常類的實例一樣。不懂?沒關系,舉例子!最實在!

[python] view plaincopy

  1. >>> assert len('love') == len('like')  
  2. >>> assert 1==1  
  3. >>> assert 1==2,"1 is not equal 2!"  
  4. Traceback (most recent call last):  
  5.   File "<stdin>", line 1, in <module>  
  6. AssertionError: 1 is not equal 2!  

我們可以看到,如果assert后面的表達式為真,則什么都不做,如果不為真,就會拋出AssertionErro異常,而且我們傳進去的字符串會作為異常類的實例的具體信息存在。其實,assert異常也可以被try塊捕獲:

[python] view plaincopy

  1. >>> try:  
  2. ...     assert 1 == 2 , "1 is not equal 2!"  
  3. ... except AssertionError,reason:  
  4. ...     print "%s:%s"%(reason.__class__.__name__,reason)  
  5. ...   
  6. AssertionError:1 is not equal 2!  
  7. >>> type(reason)  
  8. <type 'exceptions.AssertionError'>  



3.2.上下文管理(with語句)

   如果你使用try,except,finally代碼僅僅是為了保證共享資源(如文件,數據)的唯一分配,並在任務結束后釋放它,那么你就有福了!這個with語句可以讓你從try,except,finally中解放出來!語法如下:

[python] view plaincopy

  1. with context_expr [as var]:  
  2.     with_suite  

    是不是不明白?很正常,舉個例子來!

[python] view plaincopy

  1. >>> with open('/root/test.py') as f:  
  2. ...     for line in f:  
  3. ...         print line  

    上面這幾行代碼干了什么?

    (1)打開文件/root/test.py

    (2)將文件對象賦值給  f

    (3)將文件所有行輸出

     (4)無論代碼中是否出現異常,Python都會為我們關閉這個文件,我們不需要關心這些細節。

    這下,是不是明白了,使用with語句來使用這些共享資源,我們不用擔心會因為某種原因而沒有釋放他。但並不是所有的對象都可以使用with語句,只有支持上下文管理協議(context management protocol)的對象才可以,那哪些對象支持該協議呢?如下表:

file 

decimal.Context

thread.LockType

threading.Lock

threading.RLock

threading.Condition

threading.Semaphore

threading.BoundedSemaphore

    至於什么是上下文管理協議,如果你不只關心怎么用with,以及哪些對象可以使用with,那么我們就不比太關心這個問題:)

4.拋出異常(raise)

    如果我們想要在自己編寫的程序中主動拋出異常,該怎么辦呢?raise語句可以幫助我們達到目的。其基本語法如下:

[python] view plaincopy

  1. raise [SomeException [, args [,traceback]]  

    第一個參數,SomeException必須是一個異常類,或異常類的實例

    第二個參數是傳遞給SomeException的參數,必須是一個元組。這個參數用來傳遞關於這個異常的有用信息。

    第三個參數traceback很少用,主要是用來提供一個跟中記錄對象(traceback)

    下面我們就來舉幾個例子。

[python] view plaincopy

  1. >>> raise NameError  
  2. Traceback (most recent call last):  
  3.   File "<stdin>", line 1, in <module>  
  4. NameError  
  5. >>> raise NameError()  #異常類的實例  
  6. Traceback (most recent call last):  
  7.   File "<stdin>", line 1, in <module>  
  8. NameError  
  9. >>> raise NameError,("There is a name error","in test.py")  
  10. Traceback (most recent call last):  
  11.   File "<stdin>", line 1, in <module>  
  12. >>> raise NameError("There is a name error","in test.py")  #注意跟上面一個例子的區別  
  13. Traceback (most recent call last):  
  14.   File "<stdin>", line 1, in <module>  
  15. NameError: ('There is a name error', 'in test.py')  
  16. >>> raise NameError,NameError("There is a name error","in test.py")  #注意跟上面一個例子的區別  
  17. Traceback (most recent call last):  
  18.   File "<stdin>", line 1, in <module>  
  19. NameError: ('There is a name error', 'in test.py')  

    其實,我們最常用的還是,只傳入第一個參數用來指出異常類型,最多再傳入一個元組,用來給出說明信息。如上面第三個例子。

5.異常和sys模塊

    另一種獲取異常信息的途徑是通過sys模塊中的exc_info()函數。該函數回返回一個三元組:(異常類,異常類的實例,跟中記錄對象)

[python] view plaincopy

  1. >>> try:  
  2. ...     1/0  
  3. ... except:  
  4. ...     import sys  
  5. ...     tuple = sys.exc_info()  
  6. ...   
  7. >>> print tuple  
  8. (<type 'exceptions.ZeroDivisionError'>, ZeroDivisionError('integer division or modulo by zero',), <traceback object at 0x7f538a318b48>)  
  9. >>> for i in tuple:  
  10. ...     print i  
  11. ...   
  12. <type 'exceptions.ZeroDivisionError'> #異常類      
  13. integer division or modulo by zero #異常類的實例  
  14. <traceback object at 0x7f538a318b48> #跟蹤記錄對象  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM