一、什么是異常?
異常即是一個事件,該事件會在程序執行過程中發生,影響了程序的正常執行。
一般情況下,在Python無法正常處理程序時就會發生一個異常。
異常是Python對象,表示一個錯誤。
當Python腳本發生異常時我們需要捕獲處理它,否則程序會終止執行。
常見異常
# AttributeError 調用不存在的方法引發的異常
# EOFError 遇到文件末尾引發的異常
# ImportError 導入模塊出錯引發的異常
# IndexError 列表月越界引發的異常
# IOError I/O操作引發的異常,如打開文件出錯等
# KeyError 使用字典中不存在的關鍵字引發的異常
# NameError 使用不存在的變量名引發的異常
# TabError 語句塊縮進不正確引發的異常
# ValueError 搜索列表中不存在值引發的異常
# ZeroDivisionError 除數為零引發的異常
1
2
3
4
5
6
7
8
9
10
二、基礎異常處理
捕捉異常可以使用try/except語句,見下例子。
try/except語句用來檢測try語句塊中的錯誤,從而讓except語句捕獲異常信息並處理。
如果你不想在異常發生時結束你的程序,只需在try里捕獲它。
try的工作原理是,當開始一個try語句后,python就在當前程序的上下文中作標記,這樣當異常出現時就可以回到這里,try子句(與try同級的except等)先執行,接下來會發生什么依賴於執行時是否出現異常。
如果當try后的語句執行時發生異常,python就跳回到try並執行第一個匹配該異常的except子句,異常處理完畢,控制流就通過整個try語句(除非在處理異常時又引發新的異常)。
如果在try后的語句里發生了異常,卻沒有匹配的except子句,異常將被遞交到上層的try,或者到程序的最上層(這樣將結束程序,並打印缺省的出錯信息)。
如果在try子句執行時沒有發生異常,python將執行else語句后的語句(如果有else的話),然后控制流通過整個try語句。
不管在try有無異常拋出時都會執行本級try對應的finally。
基礎語法
try:
檢測異常代碼段
except:
發生異常后執行代碼段
else:
未發生異常執行代碼段
finally:
最終執行代碼段
1
2
3
4
5
6
7
8
9
例子:
print("test1")
try:
s = input()
if s is None:
print ("s 是空對象")
print(len(s)) #這句拋出異常
except TypeError:
print("類型錯誤空對象沒有長度")
else:
print("no problem")
finally:
print('end test1')
1
2
3
4
5
6
7
8
9
10
11
12
print("test1")
try:
s = None
if s is None:
print ("s 是空對象")
print(len(s)) #這句拋出異常
except TypeError:
print("類型錯誤空對象沒有長度")
else:
print("no problem")
finally:
print('end test1')
1
2
3
4
5
6
7
8
9
10
11
12
三、捕獲異常的操作
為了能夠捕獲異常,"except"語句必須有用相同的異常來拋出類對象或者字符串。
3.1 使用except而不帶任何異常類型
你可以不帶任何異常類型使用except,如下實例以上方式try-except語句捕獲所有發生的異常。但這不是一個很好的方式,我們不能通過該程序識別出具體的異常信息。因為它捕獲所有的異常。
print("test2")
try:
x = 1
y = 0
z= x/y
except:#捕獲所有異常
print('there is problem')
else:
print('no problem')
finally:
print('end test2')
1
2
3
4
5
6
7
8
9
10
11
3.2使用except而帶多種異常類型
你也可以使用相同的except語句來處理多個異常信息,這些異常將被放在一個括號里成為一個元組,如下所示:
try:
正常的操作
except(Exception1[, Exception2[,...ExceptionN]]]):
發生以上多個異常中的一個,執行這塊代碼
else:
如果沒有異常執行這塊代碼
1
2
3
4
5
6
print('test3')
try:
x = 1
y = 0
z= x/y
except (NameError,ZeroDivisionError):
print("problem is (NameError,ZeroDivisionError)")
except (RuntimeError, TypeError):
print("problem is (RuntimeError, TypeError)")
except:
print("problem")
raise
else:
print("no problem")
finally:
print('end test3')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
最后一個except子句可以忽略異常的名稱,它將被當作通配符使用。你可以使用這種方法打印一個錯誤信息,然后再次把異常拋出。
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
# except OSError as err:
# print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
for i in sys.exc_info():
print(i)
raise Exception('line xxx')
finally:
print("end")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
注意有多個expect的時候會首先執行第一個能被捕獲到的異常並且只執行一個
3.3使用多層try的時候except的傳遞
多重異常的處理
可以在try語句中嵌套另一個try語句
一旦發生異常,python匹配最近的except語句,
若是內部except能夠處理該異常,則外圍try語句不會捕獲異常。
若是不能,或者忽略,外圍try處理
內層異常捕獲失敗執行內層finally跳出外層執行異常捕獲
try:
try:
x = 1
y = 0
z= x/y
except NameError:
print ("NameError")
finally:
print ("Finally inside")
except :
print ("All exception outside")
finally:
print ("Finally outside")
1
2
3
4
5
6
7
8
9
10
11
12
13
try:
try:
x = 1
y = 0
z= x/y
except ZeroDivisionError:
print ("ZeroDivisionError")
finally:
print ("Finally inside")
except :
print ("All exception outside")
else:
print ("No exception outside")
finally:
print ("Finally outside")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
內層捕獲成功執行expect finally 執行外層else finally
四、自己拋出異常
觸發異常時候,我們可以使用raise語句自己觸發異常。raise 唯一的一個參數指定了要被拋出的異常。它必須是一個異常的實例或者是異常的類(也就是 Exception 的子類)。
如果你只想知道這是否拋出了一個異常,並不想去處理它,那么一個簡單的 raise 語句就可以再次把它拋出。
raise語法格式如下:
raise [Exception [, args [, traceback]]]
1
語句中 Exception 是異常的類型,參數標准異常中任一種,args 是自已提供的異常參數。最后一個參數是可選的(在實踐中很少使用),如果存在,是跟蹤異常對象。
print("test4")
try:
s = None
if s is None:
print ("s 是空對象")
raise NameError #如果引發NameError異常,后面的代碼將不能執行
print(len(s)) #這句不會執行,但是后面的except還是會走到
except TypeError:
print("類型錯誤空對象沒有長度")
except NameError:
print("接收到raise的異常NameError")
finally:
print('end test4')
1
2
3
4
5
6
7
8
9
10
11
12
13
拋出異常時候的參數附加顯示
print("test5")
def mye( level ):
if level < 1:
raise Exception(str(level) + " is Invalid level!")
# 觸發異常后,后面的代碼就不會再執行
try:
mye(0) # 觸發異常
except Exception as err:
print(Exception)
print(type(err))
print(err)
else:
print("successfully")
finally:
print('end test5')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
五、異常信息的詳細處理打印
使用sys模塊可以將異常詳細信息打印出來
import sys
try:
x = 1
y = 0
z= x/y
except :
t, v, tb = sys.exc_info()
print(t)
print(v)
print(tb)
1
2
3
4
5
6
7
8
9
10
捕獲異常后間接答應
def temp_convert(var):
try:
return int(var)
except ValueError as e:
print (ValueError)
print (e )
# 調用函數
temp_convert("xyz")
1
2
3
4
5
6
7
8
9
10
六、創建自己的異常
一個異常可以是一個字符串,類或對象。 Python的內核提供的異常,大多數都是實例化的類,這是一個類的實例的參數。
通過創建一個新的異常類,程序可以命名它們自己的異常。異常應該是典型的繼承自Exception類,通過直接或間接的方式。你可以通過創建一個新的異常類來擁有自己的異常。異常類繼承自 Exception 類。
在這個例子中,類 Exception 默認的 __init__() 被覆蓋。
#自定義異常
class LengthRequiredException(Exception):
def __init__(self,length,minLength):
Exception.__init__(self)
self.length = length
self.minLength = minLength
#引發自定義的異常
l = [1,2,3,4,5]
minLength = 6
try:
raise LengthRequiredException(len(l),minLength)
except IndexError:
print("index out of bounds")
except LengthRequiredException as e:
print("Length not fit :length is %d required %d" %(e.length,e.minLength))
else:
print("no exception was raised")
finally:
print("finally will be execute")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class OutOfRangeException(Exception):
def __init__(self,errMsg):
self.msg = errMsg
def __str__(self):
return self.msg
class Person(object):
def __init__(self):
self.name = None
self.age = None
def setAge(self,age):
if age < 0 or age > 100:
raise OutOfRangeException("年齡應該在0-100之間!")
self.age = age
def setName(self,name):
self.name = name
def __str__(self):
return "name:{} age:{}".format(self.name,self.age)
person = Person()
person.setName("Edward")
person.setAge(80)
print(person)
try:
person.setAge(101)
except OutOfRangeException as ex:
print(ex)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
當創建一個模塊有可能拋出多種不同的異常時,一種通常的做法是為這個包建立一個基礎異常類,然后基於這個基礎類為不同的錯誤情況創建不同的子類:
class Error(Exception):
"""Base class for exceptions in this module."""
pass
class InputError(Error):
"""Exception raised for errors in the input.
Attributes:
expression -- input expression in which the error occurred
message -- explanation of the error
"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attempts a state transition that's not
allowed.
Attributes:
previous -- state at beginning of transition
next -- attempted new state
message -- explanation of why the specific transition is not allowed
"""
def __init__(self, previous, next, message):
self.previous = previous
self.next = next
self.message = message
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
七、常用模塊
同樣的例子也可以寫成如下方式:
try:
fh = open("testfile", "w")
try:
fh.write("這是一個測試文件,用於測試異常!!")
finally:
print "關閉文件"
fh.close(http://www.my516.com)
except IOError:
print "Error: 沒有找到文件或讀取文件失敗"
1
2
3
4
5
6
7
8
9
當在try塊中拋出一個異常,立即執行finally塊代碼。
finally塊中的所有語句執行后,異常被再次觸發,並執行except塊代碼。
參數的內容不同於異常。
---------------------