1異常
1.1異常簡介
異常就是程序運行錯誤或者邏輯混亂科侈。不能讓用戶看到直接代碼的報錯已骇,需要給客戶友好的提示闭翩。
異常一般是程序中無法完全避免,一般通過一定的手段浸船,盡量減少異常的發(fā)生妄迁。提高代碼的健壯性。
看如下示例:
print('-----test--1---')
open('123.txt','r')
print('-----test--2---')
運行結果:
說明:
打開一個不存在的文件123.txt李命,當找不到123.txt文件時登淘,就會拋出給我們一個IOError類型的錯誤,No?such?file?or?directory:123.txt(沒有123.txt這樣的文件或目錄)
異常:
當Python檢測到一個錯誤時封字,解釋器就無法繼續(xù)執(zhí)行了黔州,反而出現(xiàn)了一些錯誤的提示,這就是所謂的"異常"
1.2:捕獲異常
1.2.1捕獲異常try...except...
try:
?????????? print('-----test--1---')
?????????? open('123.txt','r')
?????????? print('-----test--2---')
exceptIOError:
??????????? pass
說明:
·此程序看不到任何錯誤阔籽,因為用except捕獲到了IOError異常流妻,并添加了處理的方法
·pass表示實現(xiàn)了相應的實現(xiàn),但什么也不做笆制;如果把pass改為print語句绅这,那么就會輸出其他信息
小總結:
·
·把可能出現(xiàn)問題的代碼,放在try中
·把處理異常的代碼在辆,放在except中
1.2.2:except捕獲多個異常
看如下示例:
try:
??????? ?? printnum
exceptIOError:
?????????? print('產(chǎn)生錯誤了')
運行結果如下:
想一想:
上例程序证薇,已經(jīng)使用except來捕獲異常了,為什么還會看到錯誤的信息提示匆篓?
答:
except捕獲的錯誤類型是IOError浑度,而此時程序產(chǎn)生的異常為NameError,所以except沒有生效
修改后的代碼為:
try:
?????????? print??? num
?except??? NameError:
?????????? print('產(chǎn)生錯誤了')
運行結果如下:
實際開發(fā)中奕删,捕獲多個異常的方式俺泣,如下:
#coding=utf-8
try:
????????? print('-----test--1---')
????????? open('123.txt','r')#如果123.txt文件不存在,那么會產(chǎn)生IOError異常
????????? print('-----test--2---')
?????????? print(num)#如果num變量沒有定義完残,那么會產(chǎn)生NameError異常
except(IOError,NameError):
?????? #如果想通過一次except捕獲到多個異常可以用一個元組的方式
????????? #?errorMsg里會保存捕獲到的錯誤信息
print(errorMsg)
注意:
·當捕獲多個異常時横漏,可以把要捕獲的異常的名字谨设,放到except后,并使用元組的方式僅進行存儲
1.3:else:
咱們應該對else并不陌生缎浇,在if中扎拣,它的作用是當條件不滿足時執(zhí)行的實行;同樣在try...except...中也是如此,即如果沒有捕獲到異常二蓝,那么就執(zhí)行else中的事情
1.4:try...finally...
try...finally...語句用來表達這樣的情況:
在程序中誉券,如果一個段代碼必須要執(zhí)行,即無論異常是否產(chǎn)生都要執(zhí)行刊愚,那么此時就需要使用finally踊跟。?比如文件關閉,釋放鎖鸥诽,把數(shù)據(jù)庫連接返還給連接池等
demo:
importtime
try:
?????? f?=?open('test.txt')
????? try:
???????????? whileTrue:
??????????????????? content?=?f.readline()
????????????????? ? if len(content)?==0:
?????????????????????? break
??????????????????? time.sleep(2)
??????????????????? print(content)
except:
#如果在讀取文件的過程中商玫,產(chǎn)生了異常,那么就會捕獲到
#比如?按下了ctrl+c
??????????????? pass
finally:
??????????????? f.close()
???????????????? print('關閉文件')
except:
???????????? print("沒有這個文件")
說明:
test.txt文件中每一行數(shù)據(jù)打印牡借,但是我有意在每打印一行之前用time.sleep方法暫停2秒鐘拳昌。這樣做的原因是讓程序運行得慢一些。在程序運行的時候钠龙,按Ctrl+c中斷(取消)程序炬藤。
我們可以觀察到KeyboardInterrupt異常被觸發(fā),程序退出碴里。但是在程序退出之前刻像,finally從句仍然被執(zhí)行,把文件關閉并闲。
1.5:try嵌套中
importtime
try:
??????? f?=?open('test.txt')
??????? try:
??????????????? whileTrue:
???????????????????? content?=?f.readline()
????????????????????? if? len(content)?==0:
?????????????????????????? break
?????????????????????? time.sleep(2)
??????????????????????? print(content)
???? finally:
?????????????? f.close()
??????????????? print('關閉文件')
except:
???????????? print("沒有這個文件")
運行結果:
In?[26]:?import?time
...:?try:
...:?????f?=?open('test.txt')
...:?????try:
...:?????????while?True:
...:?????????????content?=?f.readline()
...:?????????????if?len(content)?==?0:
...:?????????????????break
...:?????????????time.sleep(2)
...:?????????????print(content)
...:?????finally:
...:?????????f.close()
...:?????????print('關閉文件')
...:?except:
...:?????print("沒有這個文件")
...:?finally:
...:?????print("最后的finally")
...:
xxxxxxx--->這是test.txt文件中讀取到信息
^C關閉文件
沒有這個文件
最后的finally
1.5.2:函數(shù)嵌套調(diào)用中
deftest1():
???????????? ? ?? print("----test1-1----")
????????????????? print(num)
????????????? ?? ? print("----test1-2----")
deftest2():
??????????????????? print("----test2-1----")
??????????????????? test1()
??????????????????? print("----test2-2----")
deftest3():
????????????? try:
????????????????????? print("----test3-1----")
?????????????????????? test1()
??????????????????????? print("----test3-2----")
except? Exceptionasresult:
?????????????????????? print("捕獲到了異常细睡,信息是:%s"%result)
????????? print("----test3-2----")
test3()
print("------華麗的分割線-----")
test2()
運行結果:
總結:
·如果try嵌套,那么如果里面的try沒有捕獲到這個異常帝火,那么外面的try會接收到這個異常溜徙,然后進行處理,如果外邊的try依然沒有捕獲到犀填,那么再進行傳遞蠢壹。。九巡。
·如果一個異常是在一個函數(shù)中產(chǎn)生的图贸,例如函數(shù)A---->函數(shù)B---->函數(shù)C,而異常是在函數(shù)C中產(chǎn)生的,那么如果函數(shù)C中沒有對這個異常進行處理冕广,那么這個異常會傳遞到函數(shù)B中疏日,如果函數(shù)B有異常處理那么就會按照函數(shù)B的處理方式進行執(zhí)行;如果函數(shù)B也沒有異常處理撒汉,那么這個異常會繼續(xù)傳遞沟优,以此類推。睬辐。挠阁。如果所有的函數(shù)都沒有處理宾肺,那么此時就會進行異常的默認處理,即通常見到的那樣
·注意觀察上圖中侵俗,當調(diào)用test3函數(shù)時锨用,在test1函數(shù)內(nèi)部產(chǎn)生了異常,此異常被傳遞到test3函數(shù)中完成了異常處理隘谣,而當異常處理完后增拥,并沒有返回到函數(shù)test1中進行執(zhí)行,而是在函數(shù)test3中繼續(xù)執(zhí)行
1.6:拋出自定義的異常
你可以用raise語句來引發(fā)一個異常洪橘。異常/錯誤對象必須有一個名字跪者,且它們應是Error或Exception類的子類
下面是一個引發(fā)異常的例子:
class?? ShortInputException(Exception):
???????????? '''自定義的異常類'''
????????????? def__init__(self,?length,?atleast):
??????????????? ? ? ? ?? #super().__init__()
??????????????????????? self.length?=?length
???????????????????????? self.atleast?=?atleast
def?? main():
?????? try:
?????????? ? s?=?input('請輸入-->?')
????????? ? ? if? len(s)?<3:
????????????????? #?raise引發(fā)一個你定義的異常
????????????????? raise? ShortInputException(len(s),3)
??????? except?? ShortInputExceptionasresult:?? #x這個變量被綁定到了錯誤的實例
?????????????????? print('ShortInputException:? 輸入的長度是%d,長度至少應是%d'%?(result.length,?result.atleast))
???????? else:
?????????????????? print('沒有異常發(fā)生.')
main()
注意
·以上程序中,關于代碼#super().__init__()的說明
這一行代碼熄求,可以調(diào)用也可以不調(diào)用渣玲,建議調(diào)用,因為__init__方法往往是用來對創(chuàng)建完的對象進行初始化工作弟晚,如果在子類中重寫了父類的__init__方法忘衍,即意味著父類中的很多初始化工作沒有做,這樣就不保證程序的穩(wěn)定了卿城,所以在以后的開發(fā)中枚钓,如果重寫了父類的__init__方法,最好是先調(diào)用父類的這個方法瑟押,然后再添加自己的功能
1.7:異常處理中拋出異常
運行結果: