詳解python with 上下文管理器
作為一個(gè) Java 為母語(yǔ)的程序員來(lái)講,學(xué)習(xí)起其他新的語(yǔ)言就難免任何事都與 Java 進(jìn)行橫向?qū)Ρ取ava 7 引入了能省去許多重復(fù)代碼的 try-with-resources
特性,不用每回 try/finally 來(lái)釋放資源(不便之處有局部變量必須聲明在 try 之前,finally 里還要嵌套 try/catch 來(lái)處理異常)。比如下面的 Java 代碼
try(InputStream inputStream = new FileInputStream("abc.txt")) { System.out.println(inputStream.read()); } catch (Exception ex) { }
它相應(yīng)的不使用 try-with-resources 語(yǔ)法的代碼就是
InputStream inputStream = null; try { inputStream = new FileInputStream("abc.txt"); } catch (Exception ex) { } finally { if(inputStream != null) { try { inputStream.close(); } catch (Exception ex) { } } }
類(lèi)似的 Python 也有自己的 try-with-resources 寫(xiě)法,就是 with 關(guān)鍵字,它的概念叫做上下文管理器(Context Manager)。
with 關(guān)鍵字的使用
with open('some_file', 'w') as opened_file: opened_file.write('Hola!')
以上的代碼相當(dāng)于
opened_file = open('some_file', 'w') try: opened_file.write('Hola!') finally: opened_file.close()
也就是 with 關(guān)鍵字打開(kāi)的資源會(huì)在 with 語(yǔ)句塊結(jié)束后自動(dòng)調(diào)用相應(yīng)的方法自動(dòng)釋放(無(wú)論 with 中操作是否有異常)。
with 用起來(lái)是很方便的,但是什么樣的資源可以用 with 關(guān)鍵字?Python 是怎么知道要調(diào)用哪個(gè)方法來(lái)關(guān)閉資源的?進(jìn)而如何實(shí)現(xiàn)自己的支持上下文管理器的 Python 類(lèi)。
再次回顧 Java 的 try-with-resources
語(yǔ)法,try(...)
括號(hào)支持的類(lèi)必須是實(shí)現(xiàn)了 AutoCloseable
接口,它的接口方法是
public void close() throws IOException
也就是 Java 的 try-with-resources
語(yǔ)法會(huì)自動(dòng)調(diào)用以上方法來(lái)釋放資源,要實(shí)現(xiàn)可被自動(dòng)釋放的 Java 就只須遵照這一規(guī)則就行。
而在 Python 中,能被 with 的類(lèi)有兩種實(shí)現(xiàn)方式
實(shí)現(xiàn)基本方法以支持上下文管理器的類(lèi)
一個(gè) Python 類(lèi)要能被用于 with
上下文,必須實(shí)現(xiàn)至少 __enter__
和 __exit__
方法。這兩個(gè)方法的意思好理解,一個(gè)是創(chuàng)建資源后,后者是退出 with
語(yǔ)句塊后。請(qǐng)看下面的例子
class File(object): def __init__(self, file_name, method): self.file_obj = open(file_name, method) def __enter__(self): print("---enter") return self.file_obj def __exit__(self, type, value, traceback): print("---exit") self.file_obj.close() with File('data.txt', 'r') as data_file: print(data_file.read())
假設(shè) data.txt 文件中的內(nèi)容是
hello
world
那么以上程序執(zhí)行后的輸出就是
--enter
hello
world
---exit
- __enter__ 返回的值作為 with ... as data_file 中的 data_file 變量的值,如果 __enter__ 沒(méi)有返回,data_file 得到的就是 NoneType object 了。
- __exit__ 可利用來(lái)釋放資源
- 沒(méi)有 __enter__ 方法試圖用 with 的寫(xiě)法執(zhí)行時(shí)會(huì)得到 AttributeErro: __enter__ 異常
- 同樣,沒(méi)有 __exit__ 方法試圖用 with 的寫(xiě)法執(zhí)行時(shí)會(huì)得到 AttributeErro: __exit__ 異常
- __exit__ 有其他額外的三個(gè)參數(shù),可獲得資源的值,以及能處理 with 塊中執(zhí)行出現(xiàn)異常的情況
- __exit__ 的返回值也有用途,如果它返回 True 則出現(xiàn)的異常不再向外傳播,其他值的話直接向外拋
利用生成器(Generator) 和裝飾器創(chuàng)建支持上下文管理器的方法
此種方式比較簡(jiǎn)單,不過(guò)邏輯控制上沒(méi)有這么強(qiáng)。
from contextlib import contextmanager @contextmanager def open_file(name, method): f = open(name, method) yield f f.close()
使用 f 的執(zhí)行代碼將被放置在 yield f
所處的位置,with
使用以上方法。yield
后的 f 變量將是 with...as
后的變量值
with open_file('some_file', 'w') as file_object: file_object.write('hola!')
這里也要注意異常處理的情況,比如把上面代碼打開(kāi)文件的模式換作 r, 仍然試圖去寫(xiě)文件,這樣在 open_file
方法的 yield f
位置將產(chǎn)生異常,會(huì)造成 f.close()
得不到執(zhí)行,不能正確釋放該資源。
欲更具防御性,前面的 yield f
可以擴(kuò)展也如下的形式
try: yield f except Exception as ex: pass #處理異常,或繼續(xù)向外拋 finally: f.close()
@contextmanager
裝飾器內(nèi)部也是封裝為一個(gè)實(shí)現(xiàn)了 __enter__
和 __exit__
方法的對(duì)象。
參考鏈接:Context Managers
以上就是詳解python with 上下文管理器的詳細(xì)內(nèi)容,更多關(guān)于python with 上下文管理器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python3中datetime庫(kù),time庫(kù)以及pandas中的時(shí)間函數(shù)區(qū)別與詳解
這篇文章主要介紹了python3中datetime庫(kù),time庫(kù)以及pandas中的時(shí)間函數(shù)區(qū)別與詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Python使用scrapy爬取陽(yáng)光熱線問(wèn)政平臺(tái)過(guò)程解析
這篇文章主要介紹了Python使用scrapy爬取陽(yáng)光熱線問(wèn)政平臺(tái)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08Python列表去重復(fù)項(xiàng)的N種方法(實(shí)例代碼)
這篇文章主要介紹了Python列表去重復(fù)項(xiàng)的N種方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-05-05基于python代碼實(shí)現(xiàn)簡(jiǎn)易濾除數(shù)字的方法
今天小編就為大家分享一篇基于python代碼實(shí)現(xiàn)簡(jiǎn)易濾除數(shù)字的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07使用TensorFlow搭建一個(gè)全連接神經(jīng)網(wǎng)絡(luò)教程
今天小編就為大家分享一篇使用TensorFlow搭建一個(gè)全連接神經(jīng)網(wǎng)絡(luò)教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02Python爬取科目四考試題庫(kù)的方法實(shí)現(xiàn)
這篇文章主要介紹了Python爬取科目四考試題庫(kù)的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03對(duì)django xadmin自定義菜單的實(shí)例詳解
今天小編就為大家分享一篇對(duì)django xadmin自定義菜單的實(shí)例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01python學(xué)習(xí)之新式類(lèi)和舊式類(lèi)講解
這篇文章主要介紹了python 新式類(lèi)和舊式類(lèi),文中比較詳細(xì)的介紹了相關(guān)內(nèi)容,有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Python實(shí)現(xiàn)清除文件夾中重復(fù)視頻
本文將利用Python中的os、hashlib、shutil模塊實(shí)現(xiàn)對(duì)文件夾中的重復(fù)視頻進(jìn)行清除,實(shí)現(xiàn)文件夾中無(wú)重復(fù)文件情況發(fā)生,需要的可以參考一下2022-05-05