日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python with和contextlib.closing配合使用(contextlib)

發布時間:2025/3/15 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python with和contextlib.closing配合使用(contextlib) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡單介紹下我認識contextlib的過程吧,覺得這個內置lib還挺有意思的。

1、

之前的我,只知道with會用來關閉文件,數據庫資源,這很好。
只要實現了__enter__() 和 __exit__()這兩個方法的類都可以輕松創建上下文管理器,就能使用with。

2、

我打開兩個數據庫的時候,都是?

with xxx as conn1:with yyy as conn2:code

真是蠢如老狗呀,其實可以:

with xxx as conn1, yyy as conn2:code

3、

總感覺離開了with block,語句體的資源(文件啊,數據庫連接啊,網絡請求呀)就會自動關閉。

可是有一天我看到contextlib.closing()。 一臉懵逼,有了with還要這個干嘛,這是我內心真實OS。。

from contextlib import closing from urllib2 import urlopenwith closing(urlopen('http://www.python.org';)) as page:for line in page:print(line)

先來否定我的想法,凡用with就萬事大吉,自動幫我關閉。

class Door(object):def open(self):print 'Door is opened'def close(self):print 'Door is closed'with Door() as d:d.open()

結果:

# 報錯: Traceback (most recent call last):File "1.py", line 38, in <module>with Door() as d: AttributeError: __exit__

果然呢,因為with語句體執行之前運行__enter__方法,在with語句體執行完后運行__exit__方法。
如果一個類如Door連這兩個方法都沒有,是沒資格使用with的。?

4、
好吧,正式認識下contextlib:https://docs.python.org/dev/library/contextlib.html
有些類,并沒有上述的兩個方法,但是有close(),能不能在不加代碼的情況下,使用with呢?
可以:?

class Door(object):def open(self):print 'Door is opened'def close(self):print 'Door is closed'with contextlib.closing(Door()) as door:door.open()

結果:

Door is opened Door is closed

contextlib.closing(xxx),原理如下:

class closing(object):"""Context to automatically close something at the end of a block.Code like this:with closing(<module>.open(<arguments>)) as f:<block>is equivalent to this:f = <module>.open(<arguments>)try:<block>finally:f.close()"""def __init__(self, thing):self.thing = thingdef __enter__(self):return self.thingdef __exit__(self, *exc_info):self.thing.close()

這個contextlib.closing()會幫它加上__enter__()和__exit__(),使其滿足with的條件。

5、
是不是只有類才能享受with的便利呀? 我單單一個方法行不行?
行!既然認識了contextlib.closing(),必須認識下contextlib.contextmanager
這是一個裝飾器,可以讓一個func()變成一個滿足with條件的類實例…?

!!!這個func()必須是生成器…
yield前半段用來表示__enter__()
yield后半段用來表示__exit__()?

from contextlib import contextmanager@contextmanager def tag(name):print("<%s>" % name)yieldprint("</%s>" % name)with tag("h1"):print 'hello world!'

結果:

<h1> hello world! </h1>

Wow,這個還真的挺酷的,以后可以用這個contextmanager來實現一些裝飾器才能做的事,

比如給一段代碼加時間cost計算:

裝飾器版本:?

import time def wrapper(func):def new_func(*args, **kwargs):t1 = time.time()ret = func(*args, **kwargs)t2 = time.time()print 'cost time=', (t2-t1)return retreturn new_func@wrapper def hello(a,b):time.sleep(1)print 'a + b = ', a+bhello(100,200)

結果:

a + b = 300 cost time= 1.00243401527

contextmanger版本:

from contextlib import contextmanager@contextmanager def cost_time():t1 = time.time()yieldt2 = time.time()print 'cost time=',t2-t1with cost_time():time.sleep(1)a = 100b = 200print 'a + b = ', a + b

?

結果:

a + b = 300 cost time= 1.00032901764

當然還是用裝飾器方便美觀點啦~

這是contextmanager原理:

  • 因為func()已經是個生成器了嘛,所以運行__enter__()的時候,contextmanager調用self.gen.next()會跑到func的yield處,停住掛起,這個時候已經有了t1=time.time()
  • 然后運行with語句體里面的語句,也就是a+b=300
  • 跑完后運行__exit__()的時候,contextmanager調用self.gen.next()會從func的yield的下一句開始一直到結束。這個時候有了t2=time.time(),t2-t1從而實現了統計cost_time的效果,完美。?
  • 源碼:

    class GeneratorContextManager(object):"""Helper for @contextmanager decorator."""def __init__(self, gen):self.gen = gendef __enter__(self):try:return self.gen.next()except StopIteration:raise RuntimeError("generator didn't yield")def __exit__(self, type, value, traceback):if type is None:try:self.gen.next()except StopIteration:returnelse:raise RuntimeError("generator didn't stop")else:if value is None:# Need to force instantiation so we can reliably# tell if we get the same exception backvalue = type()try:self.gen.throw(type, value, traceback)raise RuntimeError("generator didn't stop after throw()")except StopIteration, exc:return exc is not valueexcept:if sys.exc_info()[1] is not value:raisedef contextmanager(func):@wraps(func)def helper(*args, **kwds):return GeneratorContextManager(func(*args, **kwds))return helper

    ?

    總結

    以上是生活随笔為你收集整理的Python with和contextlib.closing配合使用(contextlib)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。