Python特性(十六):由生成器诱导的context manager

通过生成器可以很容易地构造出一个context manager对象。看下面的代码。


class MyContextManager:

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

    def __enter__(self):
        print "Entering context manager __enter__ method"
        return self.gen.next()

    def __exit__(self, exc_t, exc_v, traceback):
        print "Entering context manager __exit__ method"
        self.gen.close()

上面定义的MyContextManager类在构造时传入了一个生成器对象。而__enter__方法执行生成器对象的next方法,__exit__方法执行生成器对象的close方法。这样,context manager对象的逻辑完全在生成器对象方法中定义。从而,这里定义的MyContextManager类可以作为一个通用的类使用。


下面是一个简单生成器方法。

def simple_gen():
    print "Entering generator"
    yield "yield result"
    print "Exiting generator"


下面的with语句中利用生成器构造了一个context manager对象。

with MyContextManager(simple_gen()) as yr:
    print yr

在上面代码的第1行,分别调用context manager对象的__init__和__enter__方法。在__enter__方法调用了生成器对象的next方法。而生成器对象next方法的返回值是yield关键字后面表达式的值,也即字符串"yield result"。这个值也是生成器对象__enter__方法的返回值。这个返回值,最终传给了with语句中定义的yr变量。


下面是代码的输出。

Entering context manager __enter__ method
Entering generator
yield result
Entering context manager __exit__ method

注意:生成器对象方法的最后一个print语句并没有被执行。这是因为,当执行context manager对象的__exit__方法时,调用了生成器对象方法的close方法。而该方法的实现机制是在yield语句出抛出一个GeneratorExit的异常。这样,yield语句后面的语句当然不被执行。


猜你喜欢

转载自blog.csdn.net/hedan2013/article/details/73729425