try…finally與巢狀及自定義異常丟擲
try...finally...
try...finally...語句用來表達這樣的情況:在程式中,如果一個段程式碼必須要執行,即無論異常是否產生都要執行,那麼此時就需要使用finally。 比如檔案關閉,釋放鎖,把資料庫連線返還給連線池等。
try: f = open("log.txt","r") a = 10 b = 0 ret = a / b #捕獲多個型別的異常 except IOError as ex: print(ex) except ZeroDivisionError as ex: print(ex) else: print finally: print("無論是否異常發生,都會執行!") |
import time try: f = open('log.txt') try: while True: content = f.readline() if len(content) == 0: break time.sleep(2) print(content) except KeyboardInterrupt: #如果在讀取檔案的過程中,產生了異常,那麼就會捕獲到 #比如按下了 ctrl+c print("捕獲到了以外終止異常!") finally: f.close() print('關閉檔案') except: print("沒有這個檔案") |
test.txt檔案中每一行資料列印,但是我有意在每列印一行之前用time.sleep方法暫停2秒鐘。這樣做的原因是讓程式執行得慢一些。在程式執行的時候,按Ctrl+c中斷(取消)程式。
我們可以觀察到KeyboardInterrupt異常被觸發,程式退出。但是在程式退出之前,finally從句仍然被執行,把檔案關閉。
try巢狀
import time try: f = open('log.txt') try: while True: content = f.readline() if len(content) == 0: break time.sleep(2) print(content) finally: f.close() print('關閉檔案') except: print("沒有這個檔案") |
函式巢狀呼叫中:
def myDiv(a, b): return a / b def test2(): a = 10 b = 0 try: ret = myDiv(a, b) except: print("test02已經捕獲到了異常,但是不想處理!") #手動上拋異常 raise def test3(): try: test2() except Exception as ex: print(ex) #myDiv函式丟擲異常 #test02沒有處理,異常自動上拋 #test03接收到異常,並處理 #也就是說,異常是跨函式的 test3() |
總結:
- 如果try巢狀,那麼如果裡面的try沒有捕獲到這個異常,那麼外面的try會接收到這個異常,然後進行處理,如果外邊的try依然沒有捕獲到,那麼再進行傳遞。
- 如果一個異常是在一個函式中產生的,例如函式A---->函式B---->函式C,而異常是在函式C中產生的,那麼如果函式C中沒有對這個異常進行處理,那麼這個異常會傳遞到函式B中,如果函式B有異常處理那麼就會按照函式B的處理方式進行執行;如果函式B也沒有異常處理,那麼這個異常會繼續傳遞,以此類推。。。如果所有的函式都沒有處理,那麼此時就會進行異常的預設處理,即通常見到的那樣。
- 注意觀察上圖中,當呼叫test3函式時,在test1函式內部產生了異常,此異常被傳遞到test3函式中完成了異常處理,而當異常處理完後,並沒有返回到函式test1中進行執行,而是在函式test3中繼續執行。
自定義異常丟擲
你可以用raise語句來引發一個異常。異常/錯誤物件必須有一個名字,且它們應是Error或Exception類的子類。
下面是一個引發異常的例子:
#自定義異常類 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) if __name__ == "__main__": person = Person() person.setName("Edward") person.setAge(80) print(person) try: person.setAge(101) except OutOfRangeException as ex: print(ex) |