python中的上下文管理器以及python內建模塊contextlib的contextmanager方法
上下文管理器
上下文管理器是實現了上下文管理協議的對象,其特有的語法是“with …as”。主要用于保存和恢復各種全局狀態,關閉文件等,并為try…except…finally提供了一個方便使用的封裝。
上下文管理協議具體來說就是在類里面實現以下兩個方法:
_enter_(): 從該方法進入運行時上下文,并返回當前對象或者與運行時上下文相關的其他對象。如果with語句有as關鍵詞存在,返回值會綁定在as后的變量上。
_exit_(exc_type, exc_val, exc_tb): 退出運行時上下文,return True 如果 with 執行體有異常,則不會繼續向上拋出異常;return Flase 如果 with 執行體有異常,則繼續向上拋出異常。如果在執行with語句體時發生異常,那退出時參數會包括異常類型、異常值、異常追蹤信息,否則,3個參數都是None。
下面,我們可以自己定義一個類來通過with進行上下文管理:
class MyContextManager: def __enter__(self): print("connect to contextmanager") return self # return返回的可以是對象,會綁定給as后面的變量 def __exit__(self, exc_type, exc_val, exc_tb): """__exit__方法中: 1.如果return False:執行query_data方法有異常,則異常繼續往上拋 2.如果return True:執行query_data方法有異常,則異常不會往上拋 """ print('close the contextmanager') # return False return True def query_data(self): print('query data') with MyContextManager() as m: m.query_data()
執行以上代碼,運行結果如下:

下面,我們在類的query_data方法中增加一個報錯的a,當__exit__方法 return True 時,如下:
class MyContextManager: def __enter__(self): print("connect to contextmanager") return self # return返回的可以是對象,會綁定給as后面的變量 def __exit__(self, exc_type, exc_val, exc_tb): """__exit__方法中: 1.如果return False:執行query_data方法有異常,則異常繼續往上拋 2.如果return True:執行query_data方法有異常,則異常不會往上拋 """ print('close the contextmanager') # return False return True def query_data(self): a print('query data') with MyContextManager() as m: m.query_data()
運行結果如下:并不會執行 query_data() 方法
當__exit__方法 return False 時,如下:
class MyContextManager: def __enter__(self): print("connect to contextmanager") return self # return返回的可以是對象,會綁定給as后面的變量 def __exit__(self, exc_type, exc_val, exc_tb): """__exit__方法中: 1.如果return False:執行query_data方法有異常,則異常繼續往上拋 2.如果return True:執行query_data方法有異常,則異常不會往上拋 """ print('close the contextmanager') return False # return True def query_data(self): a print('query data') with MyContextManager() as m: m.query_data()
運行結果如下:會拋異常,

實際應用示例:
創建一個上下文管理器,這個上下文管理器將會創建一個SQLite數據庫連接,當任務處理完畢,將會將其關閉。
import sqlite3 class DataConn: def __init__(self,db_name): self.db_name = db_name def __enter__(self): self.conn = sqlite3.connect(self.db_name) return self.conn def __exit__(self,exc_type,exc_val,exc_tb): self.conn.close() if exc_val: raise if __name__ == "__main__": db = "test/test.db" with DataConn(db) as conn: cursor = conn.cursor()
在上面的代碼中,我們創建了一個類,獲取到SQLite數據庫文件的路徑。__enter__方法將會自動執行,并返回數據庫連接對象。現在我們已經獲取到數據庫連接對象,然后我們創建光標,向數據庫寫入數據或者對數據庫進行查詢。當我們退出with語句的時候,它將會調用__exit__方法用于執行和關閉這個連接。
Python的內建模塊 contextlib
對于上下文的管理,python也提供了內建的模塊contextlib來實現相同的機制,而且這種通過生成器和裝飾器實現的上下文管理器,看起來比with語句和手動實現上下文管理協議更優雅。
from contextlib import contextmanager class MyContextManager: def query_data(self): # a print('query data') @ contextmanager # 有了contextmanager我們就不需要手動實現enter和exit方法 def make_context_manager(): print('connect to contextmanager') yield MyContextManager() # yield就相當于return,但是不會結束函數,而是暫時掛起,如果我們后續需要的話,繼續調用這個函數,會從上次掛起的地方繼續執行 print('close the contextmanager') with make_context_manager() as mc: mc.query_data()

浙公網安備 33010602011771號