<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在我們日常使用場景中,經常會操作一些資源,比如檔案物件、資料庫連線、Socket連線等,資源操作完了之後,不管操作的成功與否,最重要的事情就是關閉該資源,否則資源開啟太多而沒有關閉,程式會報錯,以檔案操作為例,通常我們會這樣寫:
f = open('file.txt', 'w') try: f.write("Hello") finally: f.close()
但既然close方法是必須的操作,那就沒必要顯式地呼叫,所以Python給我們提供了一種更優雅的方式,使用with語句:
with open('file.txt', 'w') as f: f.write("Hello")
在退出with語句下的程式碼塊之後,f 物件會自動執行自己的close方法,實現資源的釋放,簡潔優雅。
上下文管理器實際是內部實現了__enter__和__exit__方法的物件。
當我們使用with語法時:
__enter__()方法:返回一個值,可以將它賦值給as後面的物件,例如上面的中的f;
__exit__()方法:with語句退出或者傳送異常時會執行這個方法。
1、__enter__方法說明
上下文管理器的__enter__方法是可以帶返回值的,預設返回None,這個返回值通過with…as…中的 as 賦給它後面的那個變數,所以 with EXPR as VAR 就是將EXPR物件__enter__方法的返回值賦給 VAR。
當然with...as...並非固定組合,單獨使用with...也是可以的,上下文管理器的__enter__方法還是正常執行,只是這個返回值並沒有賦給一個變數,with下面的程式碼塊也不能使用這個返回值。
2、__exit__方法說明
上下文管理器的__exit__方法接收3個引數exc_type、exc_val、exc_tb,如果程式碼塊BLOCK發生了異常e並退出,這3個引數分別為type(e)、str(e)、e.__traceback__,否則都為None。
同樣__exit__方法也是可以帶返回值的,這個返回值應該是一個布林型別True或False,預設為None(即False)。如果為False,異常會被丟擲,使用者需要進行例外處理。如果為True,則表示忽略該異常。
一個上下文管理器一般使用如下:
with EXPR as VAR: BLOCK
上述程式碼的執行過程等價於:
ContextManager = EXPR VAR = ContextManager.__enter__() try: BLOCK finally: ContextManager.__exit__()
f 物件就是把自己的close方法定義在了它的__exit__方法內部,實現了程式碼塊BLOCK執行完之後自動關閉自身。
下面我們定義一個檔案類,內部實現了__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語句執行:
with File('file.txt', 'w') as f: print("正在寫入...") f.write('Hello')
控制檯輸出:
進入
正在寫入...
退出
並得到了一個寫了 Hello 的 file.txt 檔案
通過try/finally語句執行:
ContextManager = File('file.txt', 'w') VAR = ContextManager .__enter__() try: print("正在寫入...") VAR.write('Hello') finally: ContextManager.__exit__()
控制檯輸出:
進入
正在寫入...
退出
並得到了一個寫了 Hello 的 file.txt 檔案
兩者輸出一致,所以驗證了二中執行過程的等價關係是正確的。
Python還提供了一個contextmanager裝飾器,允許使用者將一個生成器定義為上下文管理器,該裝飾器將生成器中的程式碼通過yield語句分成兩部分,yield之前的程式碼為__enter__方法,yield之後的程式碼為__exit__方法,yield的返回值即__enter__方法的返回值,用於賦給as後的變數。
下面我們通過contextmanager裝飾器也實現一個關於檔案的上下文管理器:
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的過程中就算出現異常,檔案也能正常關閉,當然這裡也能處理異常,使用 try/except/finally 即可。
通過with語句執行:
with open_file('file.txt', 'w') as f: print("正在寫入...") f.write('Hello')
執行結果跟之前的上下文管理器執行結果一致,說明contextmanager裝飾器也能定義一個上下文管理器。
到此這篇關於詳解Python中的上下文管理器原理的文章就介紹到這了,更多相關Python上下文管理器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45