1. 程式人生 > >python中的finally用法

python中的finally用法

來源:強哥  公眾號:Python與資料分析   連結:

https://mp.weixin.qq.com/s/6jBvyl1YoVBRyVQCdC67Sg

無論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 2

def func2():
   try:
       raise ValueError()
   except:
       return 1
   finally:
       return 3

print(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 2

def 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 3

print func1()
print func2()

上面的程式碼輸出

in func1 try: try statement, will return 1
in func1 finally: try statement, will return 2
2
in func2 try: raise error
in func2 except: caught error, will return 1!
in func2 finally: will return 3
3

我們對上面的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 3

print func2()

輸出如下

in func2 try: raise error
in func2 finally: will return 3
3

try中丟擲的異常是ValueError型別的,而except中定位的是IndexError型別的,try中丟擲的異常沒有被捕獲到,所以except中的語句沒有被執行,但不論異常有沒有被捕獲,finally還是會執行,最終函式返回了finally中的返回值3。

這裡還可以看到另外一個問題。try中丟擲的異常沒有被捕獲到,按理說當finally執行完畢後,應該被再次丟擲,但finally裡執行了return,導致異常被丟失。
可以看到在finally中使用return會導致很多問題。實際應用中,不推薦在finally中使用return返回。