Python面試之你真的理解finally了嗎?
來自專欄 Python與數據分析
無論try語句中是否拋出異常,finally中的語句一定會被執行。我們來看下面的例子:
try: f = open("/tmp/output", "w") f.write("hello") #raise Exception("something wrong")finally: print("closing file") f.close()
不論try中寫文件的過程中是否有異常,finally中關閉文件的操作一定會執行。由於finally的這個特性,finally經常被用來做一些清理工作。
我們再來看下面的例子
def func1(): try: return 1 finally: return 2def func2(): try: raise ValueError() except: return 1 finally: return 3print(func1())print(func2())
這個例子中 func1() 和 func2() 返回什麼呢?
答案是 func1() 返回2, func2() 返回3。為什麼是這樣的呢?我們先來看一段Python官網上對於finally的解釋:
A finally clause is always executed before leaving the try statement, whether an exception has occurred or not. When an exception has occurred in the try clause and has not been handled by an except clause (or it has occurred in a except or else clause), it is re-raised after the finally clause has been executed. The finally clause is also executed 「on the way out」 when any other clause of the try statement is left via a break, continue or return statement.
重點部分用粗體標出了,翻成中文就是try塊中包含break、continue或者return語句的,在離開try塊之前,finally中的語句也會被執行。
所以在上面的例子中,func1() 中,在try塊return之前,會執行finally中的語句,try中的return被忽略了,最終返回的值是finally中return的值。func2() 中,try塊中拋出異常,被except捕獲,在except塊return之前,執行finally中的語句,except中的return被忽略,最終返回的值是finally中return的值。
我們在上面的例子中加入print語句,可以更清楚地看到過程
def func1(): try: print in func1 try: try statement, will return 1 return 1 finally: print in func1 finally: try statement, will return 2 return 2def func2(): try: print in func2 try: raise error raise ValueError() except: print in func2 except: caught error, will return 1! return 1 finally: print in func2 finally: will return 3 return 3print func1()print func2()
上面的代碼輸出
in func1 try: try statement, will return 1in func1 finally: try statement, will return 22in func2 try: raise errorin func2 except: caught error, will return 1!in func2 finally: will return 33
我們對上面的func2做一些修改,如下
def func2(): try: print in func2 try: raise error raise ValueError() except IndexError: print in func2 except: caught error, will return 1! return 1 finally: print in func2 finally: will return 3 return 3print func2()
輸出如下
in func2 try: raise errorin func2 finally: will return 33
try中拋出的異常是ValueError類型的,而except中定位的是IndexError類型的,try中拋出的異常沒有被捕獲到,所以except中的語句沒有被執行,但不論異常有沒有被捕獲,finally還是會執行,最終函數返回了finally中的返回值3。
這裡還可以看到另外一個問題。try中拋出的異常沒有被捕獲到,按理說當finally執行完畢後,應該被再次拋出,但finally里執行了return,導致異常被丟失。
可以看到在finally中使用return會導致很多問題。實際應用中,不推薦在finally中使用return返回。
本文已更新微信同名公眾號,歡迎掃一掃關注~
推薦閱讀:
※ROS技術點滴 —— twist_mux多路切換器
※移動互聯網下半場剛剛開始,人工智慧就殺機四伏
※c指針與數組
※以目前的科技水平,人類何時能進入星際時代?
※讀懂這篇文章,你的孩子就離想像成真更近一步