目錄
上下文管理器類
多上下文管理器
contextmanager實(shí)現(xiàn)上下文管理器
上下文管理器(context manager)是 Python 編程中的重要概念,用于規(guī)定某個(gè)對象的使用范圍。一旦進(jìn)入或者離開該使用范圍,會有特殊操作被調(diào)用 (比如為對象分配或者釋放內(nèi)存)。它的語法形式是with...as...
為了確保一些系統(tǒng)資源得以正確釋放,我們經(jīng)常會用到 try ... excepte ... finally 語句。如:
try:
f = open('somefile')
for line in f:
print(line)
except Exception as e:
print(e)
finally:
f.close()
上面的代碼模式,從用復(fù)用代碼的模式來講,并不夠好。于是 with 語句出現(xiàn)了,通過定義一個(gè)上下文管理器來封裝這個(gè)代碼塊:
with open('filename', 'r') as f:
for line in f:
print(line)
顯然,with 語句比 try 語句簡潔了許多。
上下文管理器類
由于 with 語句利用了上下文管理器,在深入理解 with 語句之前,我們先看看上下文管理器。我們要定義一個(gè)上下文管理器其實(shí)很簡單,只要一個(gè)類實(shí)現(xiàn)了__enter__(self)和__exit__(self, exc_type, exc_valye, traceback)我們就叫他上下文管理器
__enter__(self)?返回一個(gè)對象,可以是當(dāng)前類的實(shí)例,也可以是其他對象。
class SomeThing:
def __enter__(self):
return self # 返回類實(shí)例
class LineLength:
def __init__(self, filepath):
self.__file = open(self.__filepath)
def __enter__(self):
return self.__file # 返回其他對象
執(zhí)行過程
下面讓我們看看 with 語句具體是如何執(zhí)行的。
第一步:執(zhí)行上下文表達(dá)式以獲得上下文管理器對象。上下文表達(dá)式就是 with 和 as 之間的代碼。
第二步:加載上下文管理器對象的 __exit__()方法備用。
第三步:執(zhí)行上下文管理器對象的__enter__()方法。
第四步:將__enter__()方法返回值綁定到 as 后面的 變量中。
第五步:執(zhí)行 with 內(nèi)的代碼塊。
第六步:執(zhí)行上下文管理器的__exit__()方法。
如果在代碼塊中發(fā)生了異常,異常被傳入__exit__()中。如果沒有,__exit__()的三個(gè)參數(shù)會傳入 None, None, None。__exit__()需要明確地返回 True 或 False。并且不能在__exit__()中再次拋出被傳入的異常,這是解釋器的工作,解釋器會根據(jù)返回值來確定是否繼續(xù)向上層代碼傳遞異常。當(dāng)返回 True 時(shí),異常不會被向上拋出,代碼會從報(bào)異常的代碼處跳出上下文管理繼續(xù)執(zhí)行代碼,當(dāng)返回 False 時(shí)會向上拋出,阻斷代碼執(zhí)行。當(dāng)沒有異常發(fā)生傳入__exit__()時(shí),解釋器會忽略返回值。
import time
class File(object):
def __init__(self, filename, mode):
print("上下文管理執(zhí)行順序:\n1、執(zhí)行初始化方法")
self.f = open(filename, mode)
def __enter__(self):
print("2、執(zhí)行__enter__()方法")
return self # "__enter__()方法的返回值綁定到 as 后面的 變量中
def __exit__(self, exc_type, exc_val, exc_tb):
"""
:param exc_type:如果拋出異常,返回異常類型,否則返回None
:param exc_val:如果拋出異常,返回異常內(nèi)容,否則返回None
:param exc_tb:如果拋出異常,返回異常位置,否則返回None
:return:
"""
print("4、執(zhí)行__exit__()方法")
if exc_type:
print(exc_type, "\n", exc_val, "\n", exc_tb)
# 若代碼塊報(bào)錯(cuò)則立即執(zhí)行__exit__()方法中的代碼;若代碼塊沒報(bào)錯(cuò),執(zhí)行完代碼塊后執(zhí)行__exit__()方法中的代碼"
self.f.close()
time.sleep(1)
# return True # 當(dāng)返回 True 時(shí),異常不會被向上拋出,代碼會從報(bào)異常的代碼處跳出上下文管理繼續(xù)執(zhí)行代碼,
return False # 當(dāng)返回 False 時(shí)會在__exit__()方法執(zhí)行完后向上拋出,阻斷代碼執(zhí)行。
def reads(self):
return self.f.read()
with File("README.md", "rb") as f:
print("3、執(zhí)行代碼塊代碼")
# 代碼塊部分
f.reads()
# 代碼塊報(bào)錯(cuò),報(bào)錯(cuò)后的代碼不會被執(zhí)行
print("若代碼塊報(bào)錯(cuò),“我”不被執(zhí)行;將r改為rb,代碼塊不報(bào)錯(cuò)“我”就執(zhí)行")
print("若代碼塊報(bào)錯(cuò),__exit__()方法中返回 Ture “我”才執(zhí)行;若代碼塊不報(bào)錯(cuò),“我”也執(zhí)行")
執(zhí)行結(jié)果:
把"rb"改為"r"后執(zhí)行結(jié)果:
?文章來源地址http://www.zghlxwxcb.cn/news/detail-511418.html
多上下文管理器
實(shí)際上,我們可以同時(shí)處理多個(gè)上下文管理器:
with A() as a, B() as b:
suite
所以我們大可不必寫嵌套的 with 語句。
contextmanager實(shí)現(xiàn)上下文管理器
Python還提供了一個(gè)contextmanager的裝飾器,更進(jìn)一步簡化了上下文管理器的實(shí)現(xiàn)方法。通過yield將函數(shù)分割成兩部分,yield之前的部分相當(dāng)于在__enter__方法中執(zhí)行,yield之后的部分相當(dāng)于在__exit__方法中執(zhí)行,緊跟在yield之后的返回值給as之后的變量。
from contextlib import contextmanager
class File:
def __init__(self, filename, mode):
self.f = open(filename, mode)
def reads(self):
return self.f.read()
def closed(self):
self.f.close()
@contextmanager
def read_file():
print(1)
rf = File("README.md", "rb")
yield rf
print(3)
rf.closed()
with read_file() as f:
print(2)
f.reads()
執(zhí)行結(jié)果:
?把"rb"改為"r"后執(zhí)行結(jié)果:
?注:當(dāng)報(bào)錯(cuò)后,沒有打印3,不清楚yield下面的代碼是否執(zhí)行。
-事必有法,然后有成-?最后祝大家早日達(dá)到測試的天花板!
?以下是我收集到的比較好的學(xué)習(xí)教程資源,雖然不是什么很值錢的東西,如果你剛好需要,可以評論區(qū),留言【777】直接拿走就好了文章來源:http://www.zghlxwxcb.cn/news/detail-511418.html
?
到了這里,關(guān)于Python_上下文管理器的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!