Python-with及上下文管理器——__enter__()和__exit__()

上下文管理器與裝飾器類似,它們都是包裝其他代碼的工具。但裝飾器用于包裝定義的代碼塊(如函數(shù)或類),而上下文管理器可以包裝任意格式的代碼塊。
有一些任務(wù),可能事先需要設(shè)置,事后做清理工作。這種時候用上下文管理器就可以相當(dāng)方便地進(jìn)行處理。
例如,在對文件進(jìn)行讀寫操作時,通常得這樣進(jìn)行

try:
    file = open("/tmp/foo.txt")
    data = file.read()
finally:
    file.close()

這樣的寫法雖然沒有問題,但總是需要手動關(guān)閉文件,很可能忘記關(guān)閉文件句柄,引起漏洞。

在python2.5后新增了關(guān)鍵字with,使用with語句即可進(jìn)入上下文管理器,它可以在執(zhí)行完代碼之后自動幫我們關(guān)閉文件,因此上述代碼可改寫成:

with open('test.txt') as f:
    data = f.read()

with究竟是如何工作的,或者說上面提到的上下文管理器究竟是什么?
with語句的作用實(shí)際上就是對其后的代碼求值(本例中即為調(diào)用open函數(shù))。該表達(dá)式返回一個對象,該對象包含兩個特殊方法:__enter__()__exit__()。

  • 緊跟with后面的語句被求值后,返回對象的__enter__()方法被調(diào)用,這個方法的返回值將被賦值給as后面的變量。當(dāng)with后面的代碼塊全部被執(zhí)行完之后,將調(diào)用前面返回對象的__exit__()方法。

我們可以通過如下實(shí)例來看

class Sample:
    def __enter__(self):
        print("__enter__")
        return "sample"

    def __exit__(self, type, value, trace):
        print("__exit__")


def get_sample():
    return Sample()


with get_sample() as sample:
    print(sample)
>>>
__enter__
sample
__exit__

整個過程有如下幾步:

  1. __enter__()方法被執(zhí)行
  2. __enter__()方法返回的值賦值給as后的變量sample
  3. 執(zhí)行代碼塊
  4. __exit__()方法被調(diào)用
    可以看出,with語句是進(jìn)入上下文管理器的入口且默認(rèn)執(zhí)行__enter__函數(shù),而退出上下文管理器時默認(rèn)執(zhí)行__exit__函數(shù)。

由上我們可以知道,打開和關(guān)閉資源(如文件和數(shù)據(jù)庫連接)是編寫上下文管理器的一個重要應(yīng)用。但除此之外,上下文管理器還有另一個重要功能:

異常處理

with語句的表達(dá)式的作用是返回一個遵循特定協(xié)議的對象,該對象必須定義一個 __enter__方法和一個__exit__方法。

除了self參數(shù),__enter__方法不接受任何參數(shù),如果有as變量(as子句是可選項(xiàng) ),返回值賦給as后的變量。

除了self參數(shù),__exit__方法還帶有三個位置參數(shù):

  • exc_type:一個異常類型
  • exc_instance :一個異常實(shí)例
  • traceback :一個回溯

無異常時它們?nèi)珵镹one,但如果在代碼塊內(nèi)有異常發(fā)生,則參數(shù)被填充

上下文管理器必須定義__exit__方法,該方法可以選擇性地處理包裝代碼塊中出現(xiàn)的異常,或者處理其他需要關(guān)閉上下文管理器狀態(tài)的事情。如果exit方法接收一個異常,它可以

  • 返回False實(shí)現(xiàn)異常的傳播
  • 返回True終止異常
  • 拋出一個不同的異常,它將替代異常被發(fā)送出去
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容