with and contextmanager

with

初識with

在Python中久又,讀寫文件這樣的資源要特別注意巫延,必須在使用完畢后正確關(guān)閉它們。正確關(guān)閉文件資源的一個方法是使用try...finally

try:
    f = open("/directory/filename", 'r')
    f.read()
finally:
      # 如果f不存在, 則應(yīng)該是文件對象未打開
    if f:
        f.close()

但是寫try:...finally:...非常繁瑣籽孙。Python的with語句允許我們非常方便地使用資源烈评,而不必?fù)?dān)心資源沒有關(guān)閉火俄,所以上面的代碼可以簡化為:

# 注意f只會在with語句塊有效
with open("/directory/filename", 'r') as f:
        f.read()

with的工作原理

并不是只有open()函數(shù)返回的fp對象才能使用with語句犯建。實(shí)際上,任何對象瓜客,只要正確實(shí)現(xiàn)了上下文管理适瓦,就可以用于with語句竿开。

實(shí)現(xiàn)上下文管理是通過__enter____exit__這兩個方法實(shí)現(xiàn)的. 我們可以簡單通過一個例子來說明with的內(nèi)部調(diào)用方法

class Generator(object):

    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print("There's no way out")
        return self

    def __exit__(self, exc_type, exc_value, traceback):
          # 檢查退出的類型
        # 當(dāng)有異常發(fā)生時 exc_type存在值
        if exc_type:
            print('Open the door')
        else:
            print('100%')

    def generate(self):
        print('%s can uses love to generate electricity' % self.name)

我們可以通過以下代碼調(diào)用

# 緊跟with后面的語句被求值后,返回對象的 `__enter__() `方法被調(diào)用,
# 這個方法的返回值將被賦值給as后面的變量    
with Generator("LEX") as lex:
      lex.generate()
# 當(dāng)with后面的代碼塊全部被執(zhí)行完之后玻熙,將調(diào)用返回對象的 `__exit__()`方法否彩。
用愛發(fā)電

其實(shí) with 就是這么簡單, 大部分初學(xué)者只要理解到這里就可以了, 所以小白勿入, 高能級別

高能預(yù)警

上下文管理器

我知道有很多小白還是讀了, 那我先介紹幾個名詞讓你們知男而退

  • 上下文管理協(xié)議(Context Management Protocol):包含方法 __enter____exit__,支持

該協(xié)議的對象要實(shí)現(xiàn)這兩個方法嗦随。

  • 上下文管理器(Context Manager):支持上下文管理協(xié)議的對象列荔,這種對象實(shí)現(xiàn)了

__enter____exit__方法。上下文管理器定義執(zhí)行 with 語句時要建立的運(yùn)行時上下文枚尼,

負(fù)責(zé)執(zhí)行 with 語句塊上下文中的進(jìn)入與退出操作贴浙。通常使用 with 語句調(diào)用上下文管理器,

也可以通過直接調(diào)用其方法來使用署恍。

  • 運(yùn)行時上下文(runtime context):由上下文管理器創(chuàng)建崎溃,通過上下文管理器的 __enter__

__exit__ 方法實(shí)現(xiàn),__enter__ 方法在語句體執(zhí)行之前進(jìn)入運(yùn)行時上下文盯质,__exit__

語句體執(zhí)行完后從運(yùn)行時上下文退出袁串。with 語句支持運(yùn)行時上下文這一概念。

  • 上下文表達(dá)式(Context Expression):with 語句中跟在關(guān)鍵字 with 之后的表達(dá)式呼巷,該表達(dá)式

要返回一個上下文管理器對象囱修。如 例子with后面的Generator("LEX") as lex:

  • 語句體(with-body):with 語句包裹起來的代碼塊,在執(zhí)行語句體之前會調(diào)用上下文管

理器的__enter__方法王悍,執(zhí)行完語句體之后會執(zhí)行 __exit__ 方法蔚袍。

其實(shí)這些術(shù)語不需要你們立刻理解, 只需要在以后的課程或者項(xiàng)目中慢慢體會.

@contextmanager

編寫__enter____exit__仍然很繁瑣,因此Python的標(biāo)準(zhǔn)庫contextlib提供了更簡單的寫法, 讓我們更加簡潔的定制自己的上下文管理器. 同樣的愛之代碼走起:

from context import contextmanager

class Generator(object):

    def __init__(self, name):
        self.name = name

    def generate(self):
        print('%s can uses love to generate electricity' % self.name)

@contextamnager
def create_generator(name):
      print("I'm generating electricity from love again")
      lex = Generator(name)
    # 返回給with...as...語句
    yield lex
    print('100%')

@contextmanager這個decorator必須接受一個 ==generator== 配名,用yield語句把with ... as var把變量輸出出去, 然后屬于你的上下文管理器就弄了, 是不是出奇的簡單

好久沒有這么簡單

使用一下這個管理器, 說說感覺

with create_generator("LEX") as lex:
      lex.generate()
感覺良好

@closing

但是少年郎們還沒結(jié)束呢, 讓我們了解一下closing 的作用, 它的作用就是讓不是上下文管理器的對象轉(zhuǎn)化為上下文管理器, 即可使用with語句

urllib.request import urlopen

with closing(urlopen('https://www.bilibili.com')) as page:
    for line in page:
        print(line)

其實(shí)closing內(nèi)部非常好實(shí)現(xiàn), 內(nèi)部還是調(diào)用了contextmanager方法

@contextmanager
def closing(thing):
    try:
        yield thing
    finally:
        thing.close()

closing 不同于 @contextmanager, 他的本身不需要生成器, 可謂加上這行代碼, 秒變真男人

總結(jié)

  1. with 關(guān)聯(lián)著對象的__exit____enter__方法, 你必須清楚他們是何時被調(diào)用, 他們的返回值又返回到哪里去了

  2. @contextmanager 所裝飾的對象必須是帶yield的生成器, yield 會把后面的值返回給with...as...語句

  3. @closing 原先必許在所裝飾的對象定義一個close方法, 否則會報(bào)錯, 但是現(xiàn)在不會, 所以這種一行真男人得靈藥不多了

  4. 上下文管理器將會貫穿大型框架結(jié)構(gòu), 如flask的 Application上下文, 請求(request)上下文等等, 學(xué)習(xí)上下文管理器可以幫助我們更好理解那些框架的工作原理.

未完待續(xù)...

引用

廖雪峰 contextlib

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啤咽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子渠脉,更是在濱河造成了極大的恐慌宇整,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芋膘,死亡現(xiàn)場離奇詭異鳞青,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)为朋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進(jìn)店門臂拓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人习寸,你說我怎么就攤上這事胶惰。” “怎么了霞溪?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵孵滞,是天一觀的道長中捆。 經(jīng)常有香客問我,道長坊饶,這世上最難降的妖魔是什么泄伪? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮匿级,結(jié)果婚禮上蟋滴,老公的妹妹穿的比我還像新娘。我一直安慰自己痘绎,他們只是感情好脓杉,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著简逮,像睡著了一般球散。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上散庶,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天蕉堰,我揣著相機(jī)與錄音,去河邊找鬼悲龟。 笑死屋讶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的须教。 我是一名探鬼主播皿渗,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼轻腺!你這毒婦竟也來了乐疆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤贬养,失蹤者是張志新(化名)和其女友劉穎挤土,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體误算,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡仰美,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了儿礼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咖杂。...
    茶點(diǎn)故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蚊夫,靈堂內(nèi)的尸體忽然破棺而出诉字,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布奏窑,位于F島的核電站导披,受9級特大地震影響屈扎,放射性物質(zhì)發(fā)生泄漏埃唯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一鹰晨、第九天 我趴在偏房一處隱蔽的房頂上張望墨叛。 院中可真熱鬧,春花似錦模蜡、人聲如沸漠趁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽闯传。三九已至,卻和暖如春卤妒,著一層夾襖步出監(jiān)牢的瞬間甥绿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工则披, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留共缕,地道東北人。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓士复,卻偏偏與公主長得像图谷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子阱洪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評論 2 359

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

  • 轉(zhuǎn)載自:http://mp.weixin.qq.com/s/LO1yyFeUA6pR_YPyfDoSig 姓名:梅...
    虐先森閱讀 1,424評論 0 1
  • 引言 with 語句是從 Python 2.5 開始引入的一種與異常處理相關(guān)的功能(2.5 版本中要通過 from...
    氨基鈉閱讀 350評論 0 2
  • 本文轉(zhuǎn)自淺談Python的with語句 引言 with 語句是從 Python 2.5 開始引入的一種與異常處理相...
    Syfun閱讀 4,008評論 0 50
  • contextlib — Context Manager Utilities contextlib - 上下文管理...
    英武閱讀 2,818評論 0 52
  • 術(shù)語 要使用 with 語句便贵,首先要明白上下文管理器這一概念。有了上下文管理器冗荸,with 語句才能工作嫉沽。下面是一組...
    lmem閱讀 298評論 0 0