詳解python with 上下文管理器
作為一個 Java 為母語的程序員來講,學(xué)習(xí)起其他新的語言就難免任何事都與 Java 進(jìn)行橫向?qū)Ρ取ava 7 引入了能省去許多重復(fù)代碼的 try-with-resources 特性,不用每回 try/finally 來釋放資源(不便之處有局部變量必須聲明在 try 之前,finally 里還要嵌套 try/catch 來處理異常)。比如下面的 Java 代碼
try(InputStream inputStream = new FileInputStream('abc.txt')) { System.out.println(inputStream.read());} catch (Exception ex) {}
它相應(yīng)的不使用 try-with-resources 語法的代碼就是
InputStream inputStream = null;try { inputStream = new FileInputStream('abc.txt');} catch (Exception ex) {} finally { if(inputStream != null) { try { inputStream.close(); } catch (Exception ex) { } }}
類似的 Python 也有自己的 try-with-resources 寫法,就是 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)鍵字打開的資源會在 with 語句塊結(jié)束后自動調(diào)用相應(yīng)的方法自動釋放(無論 with 中操作是否有異常)。
with 用起來是很方便的,但是什么樣的資源可以用 with 關(guān)鍵字?Python 是怎么知道要調(diào)用哪個方法來關(guān)閉資源的?進(jìn)而如何實(shí)現(xiàn)自己的支持上下文管理器的 Python 類。
再次回顧 Java 的 try-with-resources 語法,try(...) 括號支持的類必須是實(shí)現(xiàn)了 AutoCloseable 接口,它的接口方法是
public void close() throws IOException
也就是 Java 的 try-with-resources 語法會自動調(diào)用以上方法來釋放資源,要實(shí)現(xiàn)可被自動釋放的 Java 就只須遵照這一規(guī)則就行。
而在 Python 中,能被 with 的類有兩種實(shí)現(xiàn)方式
實(shí)現(xiàn)基本方法以支持上下文管理器的類
一個 Python 類要能被用于 with 上下文,必須實(shí)現(xiàn)至少 __enter__ 和 __exit__ 方法。這兩個方法的意思好理解,一個是創(chuàng)建資源后,后者是退出 with 語句塊后。請看下面的例子
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)容是
helloworld
那么以上程序執(zhí)行后的輸出就是
--enterhelloworld---exit
__enter__ 返回的值作為 with ... as data_file 中的 data_file 變量的值,如果 __enter__ 沒有返回,data_file 得到的就是 NoneType object 了。 __exit__ 可利用來釋放資源 沒有 __enter__ 方法試圖用 with 的寫法執(zhí)行時會得到 AttributeErro: __enter__ 異常 同樣,沒有 __exit__ 方法試圖用 with 的寫法執(zhí)行時會得到 AttributeErro: __exit__ 異常 __exit__ 有其他額外的三個參數(shù),可獲得資源的值,以及能處理 with 塊中執(zhí)行出現(xiàn)異常的情況 __exit__ 的返回值也有用途,如果它返回 True 則出現(xiàn)的異常不再向外傳播,其他值的話直接向外拋利用生成器(Generator) 和裝飾器創(chuàng)建支持上下文管理器的方法
此種方式比較簡單,不過邏輯控制上沒有這么強(qiáng)。
from contextlib import contextmanager @contextmanagerdef 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!’)
這里也要注意異常處理的情況,比如把上面代碼打開文件的模式換作 r, 仍然試圖去寫文件,這樣在 open_file 方法的 yield f 位置將產(chǎn)生異常,會造成 f.close() 得不到執(zhí)行,不能正確釋放該資源。
欲更具防御性,前面的 yield f 可以擴(kuò)展也如下的形式
try: yield fexcept Exception as ex: pass #處理異常,或繼續(xù)向外拋finally: f.close()
@contextmanager 裝飾器內(nèi)部也是封裝為一個實(shí)現(xiàn)了 __enter__ 和 __exit__ 方法的對象。
參考鏈接:Context Managers
以上就是詳解python with 上下文管理器的詳細(xì)內(nèi)容,更多關(guān)于python with 上下文管理器的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!
相關(guān)文章:
1. 怎樣才能用js生成xmldom對象,并且在firefox中也實(shí)現(xiàn)xml數(shù)據(jù)島?2. XHTML 1.0:標(biāo)記新的開端3. CSS3中Transition屬性詳解以及示例分享4. 低版本IE正常運(yùn)行HTML5+CSS3網(wǎng)站的3種解決方案5. ASP腳本組件實(shí)現(xiàn)服務(wù)器重啟6. css進(jìn)階學(xué)習(xí) 選擇符7. CSS Hack大全-教你如何區(qū)分出IE6-IE10、FireFox、Chrome、Opera8. ASP刪除img標(biāo)簽的style屬性只保留src的正則函數(shù)9. 告別AJAX實(shí)現(xiàn)無刷新提交表單10. ASP動態(tài)網(wǎng)頁制作技術(shù)經(jīng)驗(yàn)分享
