Python之上下文管理

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():

  

  

 

 

posted @ 2013-10-11 14:16  小郭学路  阅读(717)  评论(0编辑  收藏  举报