前言:python
在對一些資源進行訪問時,經常會出現操做不當或出現異常而致使資源沒有獲得必要關閉資源釋放資源。例如:文件讀取、socket等等。socket
下面內容以文件讀取open方法爲例。優化
原始操做:spa
1 f=open("filename") 2 f.write()#文件操做
3 f.close()
上述代碼存在的問題:3d
(1)容易忘記文件關閉。code
(2)當文件操做出現異常致使程序提前離開,而沒有執行關閉文件操做。對象
優化版:blog
1 try: 2 f=open("xxx") 3 f.write() #文件操做
4 except: 5 do something 6 finally: 7 f.close()
上述代碼:資源
雖然解決由於出現異常而致使沒有關閉文件的問題。可是這樣使得代碼冗餘度加大,最最重要的是這樣一點都不pythonic。it
with的用法:
with open("xxx") as f: f.write() #文件操做
問題來了,
with原理:
基本思想是with所求值的對象必須有一個__enter__()方法,一個__exit__()方法。
緊跟with後面的語句被求值後,返回對象的__enter__()方法被調用,這個方法的返回值將被賦值給as後面的變量。當with後面的代碼塊所有被執行完以後,將調用前面返回對象的__exit__()方法。
咱們具體來看看with爲何能夠作到自動關閉資源。
1 class Test(object): 2 def __enter__(self): 3 print("執行了 __enter__方法") 4 return "enter返回的內容" 5 6 def __exit__(self, type, value, trace): 7 print("執行了 __exit__方法") 8 9 10 with Test() as test: 11 print("test:", test)
運行結果:
執行了 __enter__方法 test: enter返回的內容 執行了 __exit__方法
執行過程分析:
推斷:自動關閉文件是在__exit__()中調用文件關閉方法。
接下咱們改進一下代碼來看看with爲何能夠處理異常出現的狀況
1 class Test(object): 2 def __enter__(self): 3 print("執行了 __enter__方法") 4 return self 5 6 def __exit__(self, type, value, trace): 7 print("執行了 __exit__方法") 8 print("type:", type) 9 print("value:", value) 10 print("trace:", trace) 11 12 def do_something(self): 13 bar = 1 / 0 14 return bar + 10 15 16 17 with Test() as test: 18 test.do_something()
運行結果:
先給分析一下代碼,Test()的__enter__()
方法返回新建立的Test對象,並賦值給變量test。而後執行會出現異常的方法,__exit__()中打印其三個參數。
根據運行結果,很明顯__exit__()得三個參數分別是異常類、異常值、異常信息追蹤。
實際上,當with中間代碼體出現異常時__enter__()就會執行,並把異常相關信息賦值給三參數。同時在這個方法中咱們還能夠加入清理資源,關閉文件等等操做。
總的看來,python的with語句是一個十分巧妙有效的機制,它可讓代碼更加的簡潔、更加的pythonic。