一、什么是異常
1.錯誤
從軟件方面來說,錯誤是語法或是邏輯上的。錯誤是語法或是邏輯上的。
語法錯誤指示軟件的結構上有錯誤,導致不能被解釋器解釋或編譯器無法編譯。這些些錯誤必須在程序執行前糾正。
當程序的語法正確后,剩下的就是邏輯錯誤了。邏輯錯誤可能是由於不完整或是不合法的輸入所致;
在其它情況下,還可能是邏輯無法生成、計算、或是輸出結果需要的過程無法執行。這些錯誤通常分別被稱為域錯誤和范圍錯誤。
當python檢測到一個錯誤時,python解釋器就會指出當前流已經無法繼續執行下去。這時候就出現了異常。
2.異常
對異常的最好描述是:它是因為程序出現了錯誤而在正常控制流以外采取的行為。
這個行為又分為兩個階段:首先是引起異常發生的錯誤,然后是檢測(和采取可能的措施)階段。
第一階段是在發生了一個異常條件(有時候也叫做例外的條件)后發生的。
只要檢測到錯誤並且意識到異常條件,解釋器就會發生一個異常。引發也可以叫做觸發,拋出或者生成。解釋器通過它通知當前控制流有錯誤發生。
python也允許程序員自己引發異常。無論是python解釋器還是程序員引發的,異常就是錯誤發生的信號。
當前流將被打斷,用來處理這個錯誤並采取相應的操作。這就是第二階段。
對於異常的處理發生在第二階段,異常引發后,可以調用很多不同的操作。
可以是忽略錯誤(記錄錯誤但不采取任何措施,采取補救措施后終止程序。)或是減輕問題的影響后設法繼續執行程序。
所有的這些操作都代表一種繼續,或是控制的分支。關鍵是程序員在錯誤發生時可以指示程序如何執行。
python用異常對象(exception object)來表示異常。遇到錯誤后,會引發異常。
如果異常對象並未被處理或捕捉,程序就會用所謂的回溯(traceback)終止執行,就像下面這樣。
>>> 1/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero
類似python這樣支持引發和處理異常的語言,可以讓開發人員在錯誤發生時更直接的控制它們。
程序員不僅有了檢測錯誤的能力,還可以在它們發生時采取更可靠的補救措施。由於有了運行時管理錯誤的能力,應用程序的健壯性有了很大的提高。
二、python中常見的異常
在python2中可以通過一個模塊來查看所有的內置異常,而在python3中就無法查看。
>>> import exceptions >>> dir(exceptions) ['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BufferError', 'BytesWarning', 'DeprecationWarning', 'EOFError', 'EnvironmentError', 'Exception', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'KeyError', 'KeyboardInterrupt', 'LookupError', 'MemoryError', 'NameError', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'ReferenceError', 'RuntimeError', 'RuntimeWarning', 'StandardError', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'WindowsError', 'ZeroDivisionError', '__doc__', '__name__', '__package__']
下面介紹介幾個使用的比較頻繁的異常。
1.NameError:嘗試訪問一個未申明的變量。
>>> foo Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'foo' is not defined
NameError表示我們訪問了一個沒有初始化的變量。
任何可訪問的變量必須在名稱空間里列出,訪問變量需要由解釋器進行搜索,如果請求的名字沒有在任何名稱空間里找到,那么就會生成一個NameError異常。
2.ZeroDivisionError:除數為0.
>>> 1/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero
任何一個數值被零除都會導致ZeroDivisionError異常。
3.SyntaxError:python解釋器語法錯誤。
>>> for i in li: ... print i File "<stdin>", line 2 print i ^ SyntaxError: Missing parentheses in call to 'print'. Did you mean print(i)?
SyntaxError異常是唯一不是在運行時發生的異常。
它代表python代碼中有一個不正確的結構,在他改正之前程序無法運行。
這些錯誤一般都是在編譯時發生的,python解釋器無法把你的腳本轉化成python字節代碼。
4.IndexError:請求的索引超出范圍。
>>> li [1, 2, 3, 4] >>> li[10] Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: list index out of range
5.KeyError:請求一個不存在的字典關鍵字。
>>> dict1 = {"name":'kebi',"sex":'boy'} >>> dict1['age'] Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'age'
6.IOError/FileNotFoundError:輸入/輸出錯誤
類似嘗試打開一個不存在的磁盤文件一類的操作會引發一個操作系統輸入/輸出錯誤。
在python2中引發IOError異常;在python3中引發/FileNotFoundError異常。
#在python2中 >>> f = open('helo') Traceback (most recent call last): File "<stdin>", line 1, in <module> IOError: [Errno 2] No such file or directory: 'helo' #在python3中 >>> f = open('blah') Traceback (most recent call last): File "<stdin>", line 1, in <module> FileNotFoundError: [Errno 2] No such file or directory: 'blah'
7.AttributeError:嘗試訪問未知的對象屬性。
>>> class myClass(object): ... pass ... >>> myInst = myClass() >>> myInst.foo Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'myClass' object has no attribute 'foo'
三、檢測和處理異常
異常可以通過try語句來檢測。任何在try語句塊里的代碼都會被監測,檢查有無異常發生。
一個try語句可以對應多個expect語句,但只能對應一個finally子句,或是一個try-expect-finally復合語句。
你可以使用try-expect語句檢測和處理異常,你也可以添加一個可選的else子句處理有沒有探測到異常的執行代碼。
而finally只允許檢測異常並做一些必要的清楚工作(無論發生錯誤與否),沒有任何異常處理設施。
1.try-expect語句
try-expect語句(以及其更復雜的形式)定義了進行異常監控的一段代碼,並提供了處理異常的機制。
>>> try: ... a #監控這里的異常 ... except NameError: ... print("警告") #異常處理代碼 ... 警告
正常情況下:
>>> try: ... a=1 ... except NameError: ... print("警告") ...
在程序運行時,解釋器嘗試執行try塊里所有的代碼,如果代碼完成后沒有發生異常,執行流會忽略except語句繼續執行。
而當except語句所制定的異常發生后,我們保存了錯誤的原因,控制流會立即跳轉到對應的處理器(try子句的剩余語句會被忽略。)
2.多個expect子句
try: x = int(input("frist num>>>")) y = int(input("second num>>>")) print(x/y) except ValueError: print("只能是數字") except ZeroDivisionError: print("除數不能為0") #執行結果 frist num>>>a 只能是數字 frist num>>>2 second num>>>0 除數不能為0
3.用一個塊捕捉多個異常
except語句在處理多個異常時要求異常被放在一個元祖里。
try: x = int(input("frist num>>>")) y = int(input("second num>>>")) print(x/y) except (ValueError,ZeroDivisionError): print("輸入有誤") #執行結果 frist num>>>a 輸入有誤
4.捕獲所有異常
使用Exception可以截獲所有異常。
try: x = int(input("frist num>>>")) y = int(input("second num>>>")) print(x/y) except Exception as e: print("輸入有誤",e) #執行結果 frist num>>>tyui 輸入有誤 invalid literal for int() with base 10: 'tyui'
注意:
python提供給程序員的try-expect語句是為了更好的跟蹤潛在的錯誤並在代碼里准備好處理異常的邏輯。
但是盡量不要把大片的代碼裝入try-except中然后使用pass忽略掉錯誤。