詳解Python中的上下文管理器原理
with語句
在我們日常使用場景中,經常會操作一些資源,比如文件對象、數(shù)據(jù)庫連接、Socket連接等,資源操作完了之后,不管操作的成功與否,最重要的事情就是關閉該資源,否則資源打開太多而沒有關閉,程序會報錯,以文件操作為例,通常我們會這樣寫:
f = open('file.txt', 'w')
try:
f.write("Hello")
finally:
f.close()
但既然close方法是必須的操作,那就沒必要顯式地調用,所以Python給我們提供了一種更優(yōu)雅的方式,使用with語句:
with open('file.txt', 'w') as f:
f.write("Hello")
在退出with語句下的代碼塊之后,f 對象會自動執(zhí)行自己的close方法,實現(xiàn)資源的釋放,簡潔優(yōu)雅。
上下文管理器原理
上下文管理器實際是內部實現(xiàn)了__enter__和__exit__方法的對象。
當我們使用with語法時:
__enter__()方法:返回一個值,可以將它賦值給as后面的對象,例如上面的中的f;
__exit__()方法:with語句退出或者發(fā)送異常時會執(zhí)行這個方法。
1、__enter__方法說明
上下文管理器的__enter__方法是可以帶返回值的,默認返回None,這個返回值通過with…as…中的 as 賦給它后面的那個變量,所以 with EXPR as VAR 就是將EXPR對象__enter__方法的返回值賦給 VAR。
當然with...as...并非固定組合,單獨使用with...也是可以的,上下文管理器的__enter__方法還是正常執(zhí)行,只是這個返回值并沒有賦給一個變量,with下面的代碼塊也不能使用這個返回值。
2、__exit__方法說明
上下文管理器的__exit__方法接收3個參數(shù)exc_type、exc_val、exc_tb,如果代碼塊BLOCK發(fā)生了異常e并退出,這3個參數(shù)分別為type(e)、str(e)、e.__traceback__,否則都為None。
同樣__exit__方法也是可以帶返回值的,這個返回值應該是一個布爾類型True或False,默認為None(即False)。如果為False,異常會被拋出,用戶需要進行異常處理。如果為True,則表示忽略該異常。
一個上下文管理器一般使用如下:
with EXPR as VAR:
BLOCK
上述代碼的執(zhí)行過程等價于:
ContextManager = EXPR
VAR = ContextManager.__enter__()
try:
BLOCK
finally:
ContextManager.__exit__()
f 對象就是把自己的close方法定義在了它的__exit__方法內部,實現(xiàn)了代碼塊BLOCK執(zhí)行完之后自動關閉自身。
自定義上下文管理器
下面我們定義一個文件類,內部實現(xiàn)了__enter__和__exit__兩個方法:
class File:
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
print("進入")
self.f = open(self.filename, self.mode)
return self.f
def __exit__(self, exc_type=None, exc_val=None, exc_tbs=None):
print("退出")
self.f.close()
這時候File類就是一個上下文管理器
我們分別通過 with語句 和 try/finally語句 使用File類對文件進行寫入操作
通過with語句執(zhí)行:
with File('file.txt', 'w') as f:
print("正在寫入...")
f.write('Hello')
控制臺輸出:
進入
正在寫入...
退出
并得到了一個寫了 Hello 的 file.txt 文件
通過try/finally語句執(zhí)行:
ContextManager = File('file.txt', 'w')
VAR = ContextManager .__enter__()
try:
print("正在寫入...")
VAR.write('Hello')
finally:
ContextManager.__exit__()
控制臺輸出:
進入
正在寫入...
退出
并得到了一個寫了 Hello 的 file.txt 文件
兩者輸出一致,所以驗證了二中執(zhí)行過程的等價關系是正確的。
contextmanager 裝飾器
Python還提供了一個contextmanager裝飾器,允許用戶將一個生成器定義為上下文管理器,該裝飾器將生成器中的代碼通過yield語句分成兩部分,yield之前的代碼為__enter__方法,yield之后的代碼為__exit__方法,yield的返回值即__enter__方法的返回值,用于賦給as后的變量。
下面我們通過contextmanager裝飾器也實現(xiàn)一個關于文件的上下文管理器:
from contextlib import contextmanager
@contextmanager
def open_file(filename, mode):
print('進入')
f = open(filename, mode)
try:
yield f
finally:
print('退出')
f.close()
說明:這里使用 try/finally 是確保yield的過程中就算出現(xiàn)異常,文件也能正常關閉,當然這里也能處理異常,使用 try/except/finally 即可。
通過with語句執(zhí)行:
with open_file('file.txt', 'w') as f:
print("正在寫入...")
f.write('Hello')
執(zhí)行結果跟之前的上下文管理器執(zhí)行結果一致,說明contextmanager裝飾器也能定義一個上下文管理器。
到此這篇關于詳解Python中的上下文管理器原理的文章就介紹到這了,更多相關Python上下文管理器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用Django實現(xiàn)文章與多個標簽關聯(lián)的示例詳解
在構建一個博客或內容管理系統(tǒng)時,經常需要實現(xiàn)文章與標簽的關聯(lián),在 Django 中,我們可以利用 ManyToManyField 來實現(xiàn)文章與標簽的多對多關系,在本文中,我們將詳細探討如何使用 Django 模型實現(xiàn)文章與多個標簽的關聯(lián),需要的朋友可以參考下2023-11-11
用TensorFlow實現(xiàn)多類支持向量機的示例代碼
這篇文章主要介紹了用TensorFlow實現(xiàn)多類支持向量機的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
Python tkinter實現(xiàn)桌面軟件流程詳解
這篇文章主要介紹了Python tkinter做一個好用的桌面軟件,100%你會愛上它,文中的示例代碼講解詳細,快跟小編一起動手試一試吧2022-10-10
python?實現(xiàn)?pymysql?數(shù)據(jù)庫操作方法
這篇文章主要介紹了python實現(xiàn)pymysql數(shù)據(jù)庫操作方法,文章基于python的相關內容展開對?pymysql?數(shù)據(jù)庫操作方法的詳細介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-04-04

