python 初次认识with 和 contextlib.closing
2017-09-26 19:14
453 查看
简单介绍下我认识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。。
先来否定我的想法,凡用with就万事大吉,自动帮我关闭。
果然呢,因为with语句体执行之前运行__enter__方法,在with语句体执行完后运行__exit__方法。
如果一个类如Door连这两个方法都没有,是没资格使用with的。
4、
好吧,正式认识下contextlib:https://docs.python.org/dev/library/contextlib.html
有些类,并没有上述的两个方法,但是有close(),能不能在不加代码的情况下,使用with呢?
可以:
5、
是不是只有类才能享受with的便利呀? 我单单一个方法行不行?
行!既然认识了contextlib.closing(),必须认识下contextlib.contextmanager
这是一个装饰器,可以让一个func()变成一个满足with条件的类实例…
!!!这个func()必须是生成器…
yield前半段用来表示__enter__()
yield后半段用来表示__exit__()
<h1>
hello world!
</h1>
Wow,这个还真的挺酷的,以后可以用这个contextmanager来实现一些装饰器才能做的事,
比如给一段代码加时间cost计算:
装饰器版本:
a + b = 300
cost time= 1.00243401527
contextmanger版本:
a + b = 300
cost time= 1.00032901764
当然还是用装饰器方便美观点啦~
这是contextmanager原理:
1、因为func()已经是个生成器了嘛,所以运行__enter__()的时候,contextmanager调用self.gen.next()会跑到func的yield处,停住挂起,这个时候已经有了t1=time.time()
2、然后运行with语句体里面的语句,也就是a+b=300
3、跑完后运行__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 = gen
def __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:
return
else:
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 back
value = type()
try:
self.gen.throw(type, value, traceback)
raise RuntimeError("generator didn't stop after throw()")
except StopIteration, exc:
return exc is not value
except:
if sys.exc_info()[1] is not value:
raise
def contextmanager(func):
@wraps(func)
def helper(*args, **kwds):
return GeneratorContextManager(func(*args, **kwds))
return helper
以上
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 urlopen with 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 closedcontextlib.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 = thing def __enter__(self): return self.thing def __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) yield print("</%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 ret return new_func @wrapper def hello(a,b): time.sleep(1) print 'a + b = ', a+b hello(100,200)结果:
a + b = 300
cost time= 1.00243401527
contextmanger版本:
from contextlib import contextmanager @contextmanager def cost_time(): t1 = time.time() yield t2 = time.time() print 'cost time=',t2-t1 with cost_time(): time.sleep(1) a = 100 b = 200 print 'a + b = ', a + b结果:
a + b = 300
cost time= 1.00032901764
当然还是用装饰器方便美观点啦~
这是contextmanager原理:
1、因为func()已经是个生成器了嘛,所以运行__enter__()的时候,contextmanager调用self.gen.next()会跑到func的yield处,停住挂起,这个时候已经有了t1=time.time()
2、然后运行with语句体里面的语句,也就是a+b=300
3、跑完后运行__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 = gen
def __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:
return
else:
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 back
value = type()
try:
self.gen.throw(type, value, traceback)
raise RuntimeError("generator didn't stop after throw()")
except StopIteration, exc:
return exc is not value
except:
if sys.exc_info()[1] is not value:
raise
def contextmanager(func):
@wraps(func)
def helper(*args, **kwds):
return GeneratorContextManager(func(*args, **kwds))
return helper
以上
相关文章推荐
- python中的with与@contextlib.contextmanager
- python中with和contextlib的用法
- python中关于with及contextlib的用法
- python中关于with及contextlib的用法
- python中关于with及contextlib的用法
- python中关于with以及contextlib的使用
- python contextlib.closing()
- Python中with及contextlib的用法详解
- python学习笔记:利用contextlib和@contextmanager实现with语句上下文实例
- python with 和 contextlib
- python_关于with及contextlib的用法
- python的上下文管理(contextlib)(2)
- Python with Context Managers
- Python contextlib.contextmanager
- Python contextlib模块使用示例
- RF源码阅读(碎片纪录)-Python积木之contextlib
- Python:contextlib模块——上下文管理器工具
- @contextmanager:Python实现with结构的好方法
- python contextlib.py
- python contextlib