一、什么是上下文管理器候学?
上下文管理器類型是python的內(nèi)置類型之一歧寺,上下文管理器的定義:允許用戶自定義類來(lái)定義運(yùn)行時(shí)上下文,在語(yǔ)句體被執(zhí)行前進(jìn)入該上下文揣云,并在語(yǔ)句執(zhí)行完畢時(shí)退出該上下文捕儒。
二、上下文管理器有什么用邓夕?
對(duì)于系統(tǒng)資源如文件刘莹、數(shù)據(jù)庫(kù)連接、socket 而言焚刚,應(yīng)用程序打開(kāi)這些資源并執(zhí)行完業(yè)務(wù)邏輯之后点弯,必須做的一件事就是要關(guān)閉(斷開(kāi))該資源。例如我們經(jīng)常寫(xiě)的
try:
f.write("hello,world")
except IOError:
print("oops error")
finally:
f.close()
這樣寫(xiě)是沒(méi)有什么問(wèn)題矿咕,但python針對(duì)這種運(yùn)行抢肛、退出都需要執(zhí)行特定任務(wù)的場(chǎng)景,提供了一種更簡(jiǎn)潔的運(yùn)行方式碳柱,也就是上下文管理器捡絮。
三、上下文管理器協(xié)議
上下文管理器是用戶自定義的莲镣,只要一個(gè)類實(shí)現(xiàn)了上下文管理器協(xié)議(兩個(gè)方法)福稳,就是一個(gè)上下文管理器。
contextmanager.__enter__()
進(jìn)入運(yùn)行時(shí)上下文并返回此對(duì)象或關(guān)聯(lián)到該運(yùn)行時(shí)上下文的其他對(duì)象瑞侮。 此方法的返回值會(huì)綁定到使用此上下文管理器的 with 語(yǔ)句的 as 子句中的標(biāo)識(shí)符的圆。
contextmanager.__exit__(*exc_type*, *exc_val*, *exc_tb*)
退出運(yùn)行時(shí)上下文并返回一個(gè)布爾值旗標(biāo)來(lái)表明所發(fā)生的任何異常是否應(yīng)當(dāng)被屏蔽鼓拧。 如果在執(zhí)行 with 語(yǔ)句的語(yǔ)句體期間發(fā)生了異常,則參數(shù)會(huì)包含異常的類型越妈、值以及回溯信息毁枯。 在其他情況下三個(gè)參數(shù)均為 None。
四叮称、如何使用上下文管理器
上下文管理器要配合 with ... as ...
語(yǔ)句使用.
在進(jìn)入 with
語(yǔ)句塊時(shí)种玛,會(huì)執(zhí)行上下文管理器的__enter__()
,并將返回值賦值給 as
后面的對(duì)象瓤檐。
當(dāng)離開(kāi) with
語(yǔ)句塊赂韵,會(huì)執(zhí)行上下文管理器的__exit__(exc_type, exc_val, exc_tb)
,以確保我們想要的動(dòng)作能夠執(zhí)行挠蛉。
例如:實(shí)現(xiàn)一個(gè)打開(kāi)文件的上下文管理器
class FileContextManager():
def__init__(self, filename, mode):
self.filename = filename
self.mode = mode
def__enter__(self):
print("entering")
self.f = open(self.filename,self.mode)
return self.f
def__exit__(self, exc_type, exc_val, exc_tb):
print("will exit")
self.f.close()
with FileContextManager('test.txt','w') as f:
f.write('hello,world')
五祭示、contextmanager 上下文裝飾器
通過(guò) yield
將函數(shù)分割成兩部分,yield
之前的語(yǔ)句在 __enter__
方法中執(zhí)行谴古,yield
之后的語(yǔ)句在 __exit__
方法中執(zhí)行质涛。緊跟在 yield
后面的值是函數(shù)的返回值(交與 as
后面的標(biāo)識(shí)符)。
from contextlib import contextmanager
@contextmanager
def managed_resource(*args,**kwds):
# 打開(kāi)資源
resource=open_resource(*args,**kwds)
try:
yield resource
finally:
# 釋放資源
release_resource(resource)
參考:
https://docs.python.org/zh-cn/3/library/stdtypes.html#context-manager-types