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

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

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

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

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

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

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

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

我們可以通過如下實例來看

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語句是進入上下文管理器的入口且默認執(zhí)行__enter__函數(shù),而退出上下文管理器時默認執(zhí)行__exit__函數(shù)偶器。

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

異常處理

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

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

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

  • exc_type:一個異常類型
  • exc_instance :一個異常實例
  • traceback :一個回溯

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

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

  • 返回False實現(xiàn)異常的傳播
  • 返回True終止異常
  • 拋出一個不同的異常昂灵,它將替代異常被發(fā)送出去
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末避凝,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子眨补,更是在濱河造成了極大的恐慌管削,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件撑螺,死亡現(xiàn)場離奇詭異含思,居然都是意外死亡,警方通過查閱死者的電腦和手機实蓬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進店門茸俭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人安皱,你說我怎么就攤上這事调鬓。” “怎么了酌伊?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵腾窝,是天一觀的道長。 經(jīng)常有香客問我居砖,道長虹脯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任奏候,我火速辦了婚禮循集,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔗草。我一直安慰自己咒彤,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布咒精。 她就那樣靜靜地躺著镶柱,像睡著了一般。 火紅的嫁衣襯著肌膚如雪模叙。 梳的紋絲不亂的頭發(fā)上歇拆,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天,我揣著相機與錄音,去河邊找鬼故觅。 笑死厂庇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的输吏。 我是一名探鬼主播宋列,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼评也!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灭返,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤盗迟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后熙含,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體罚缕,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年怎静,在試婚紗的時候發(fā)現(xiàn)自己被綠了邮弹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚓聘,死狀恐怖腌乡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夜牡,我是刑警寧澤与纽,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站塘装,受9級特大地震影響急迂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蹦肴,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一僚碎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧阴幌,春花似錦勺阐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至背零,卻和暖如春腰吟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工毛雇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留嫉称,地道東北人。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓灵疮,卻偏偏與公主長得像织阅,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子震捣,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容