http://www.cnblogs.com/coser/archive/2013/01/28/2880328.html
上下文管理协议为代码块提供包含初始化和清理操作的上下文环境。即便代码块发生异常,清理操作也会被执行。
Context对象
*__enter__:初始化环境,返回上下文对象
*__exit__:执行清理操作。返回True时,将阻止异常向外传递
#!/usr/bin/env python26 #-*- coding:utf-8 -*- class MyContext(object): def __init__(self,*args): self._data = args def __enter__(self): print "__enter__" return self._data #不一定要返回上下文对象自身 def __exit__(self,exc_type,exc_value,traceback): if exc_type: print "Exception:",exc_value print "__exit__" return True#阻止异常向外传递 with MyContext(1,2,3) as data: #将__enter__返回的对象赋给data print data print '*'*30 with MyContext(1,2,3): #发生异常,显示并拦截 raise Exception("data error!")
输出:
__enter__
(1, 2, 3)
__exit__
******************************
__enter__
Exception: data error!
__exit__
上面的模式,需要重写__enter__和__exit__,比较麻烦。contextlib可以解决这个问题。
contextlib
标准库contextlib提供一个contextmanager装饰器,用来简化上下文类型开发。
#!/usr/bin/env python26 #-*- coding: utf-8 -*- from contextlib import contextmanager @contextmanager def closing(o): print "__enter__" yield o print "__exit__" o.close() with closing(open("readme.txt","r")) as f: print f.readline(),
contextmanger替我们创建Context对象,并利用yield切换执行过程。
*通过__enter__调用closing函数,将yield结果作为__enter__返回值
*yield让出closing执行权限,转而执行with代码块
*执行完毕,__exit__发生消息,通知yield恢复执行closing后续代码
contextmanger让我们少写很多代码,因为不是自己写__exit__,所以得额外处理异常。
上下文管理协议的用途很广,比如:
1、Synchronized:为代码块提供lock/unlock线程同步;
2、DBContext:为代码块中的逻辑提供共享的数据库连接,并负责关闭连接。
此处先记着,待等到实际应用的时候再更新相关的理解。
具体的例子
1、计算函数的执行时间:
import time class Context(object): def __init__(self): self.start = None self.end = None def __enter__(self): self.start = time.time() print "Start" return self def __exit__(self, exctype, excvalue, traceback): print "exit" self.end = time.time() print "End:" print 'Cost:%d' % (self.end - self.start) return self def test(): return Context() with test(): print 'int test' time.sleep(2)
输出结果:
Start int test exit End: Cost:2
2、使用装饰器的方式
#在装饰器内部使用with语法 def with_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): with Context(): return func(*args, **kwargs) return wrapper @with_decorator def test_decorator():