python contextlib.py

"""Utilities for with-statement contexts.  See PEP 343."""


import sys

from functools import wraps

from warnings import warn


#这个模块定义了三个类:contextmanager、nested、closing

#其中比较常用的是contextmanager和closing

__all__ = ["contextmanager", "nested", "closing"]



class GeneratorContextManager(object):

    """Helper for @contextmanager decorator."""

    #类实例化完成后调用此方法完成一些初始化工作

    #很明显,我们实例化此类时需要传递一个generator作为其初始化参数

    def __init__(self, gen):

        self.gen = gen


    #如果我们自己去实现一个上下文管理器,那么我们必须显示实现对应的__enter__和__exit__方法

    #从后文我们可以知道,我们使用一个generator来初始化了本类

    #而本类的意图也是在__enter__和__exit__中将generator中yield的前后两部分代码分别放在__enter__和__exit__中

    #分别完成初始化操作(setup)和清理操作(cleanup)

    def __enter__(self):

        try:

            #这里return值就是generator中yield后面跟随的值,也是我们在with...as variable中返回给variable的值

            return self.gen.next()

        except StopIteration:

            raise RuntimeError("generator didn't yield")


    #这里是执行yield后面的代码

    #一般而言,我们的generator具有如下格式:

    """

            <setup>

            try:

                yield <value>

            finally:

                <cleanup>

    """

    #必须以generatorFunction().next()方式去驱动此generator执行,next()方法执行的分界点就是yield语句,yield后面跟随的变量作为next()方法的返回值

    #第一次我们在__enter__中执行第一次next()方法,那么generator中<setup>部分代码开始运行,next()方法执行到yield后暂停返回

    #当我们第二次执行generator.next()时,继续从第一次所遇到的yield处向下执行,如果到程序结尾仍没有发现yield语句,那么会raise StopIteration(此行为是我们所期望的)

    def __exit__(self, type, value, traceback):

        if type is None:

            #这里我们捕捉我们所期望的StopIteration异常

            try:

                #相当于执行generator的finally后面的语句

                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:

                # Suppress the exception *unless* it's the same exception that

                # was passed to throw().  This prevents a StopIteration

                # raised inside the "with" statement from being suppressed

                return exc is not value

            except:

                # only re-raise if it's *not* the exception that was

                # passed to throw(), because __exit__() must not raise

                # an exception unless __exit__() itself failed.  But throw()

                # has to raise the exception to signal propagation, so this

                # fixes the impedance mismatch between the throw() protocol

                # and the __exit__() protocol.

                #

                if sys.exc_info()[1] is not value:

                    raise


#这是一个装饰器函数,这个装饰器函数用来装饰我们的generator,在装饰器返回的新的函数中用我们的generator去初始化GeneratorContextManager

#最终在with语句中,执行装饰器返回的新函数,新函数的返回值是我们用我们定义的generator初始化的GeneratorContextManager对象

#这个对象具有__enter__、__exit__方法(实现上下文管理器)

#在__enter__中,我们返回给as后的variable值为原generator的yield后跟随的变量,此后我们用这个句柄去执行操作

#在__exit__中,我们执行对应的清理操作。(例如执行句柄的关闭操作)

def contextmanager(func):

    """@contextmanager decorator.


    Typical usage:

        #下面揭示了本module的用法--用装饰器装饰我们的generator,将我们的generator作为参数去初始化那么最终我们generator的返回值是一个上下文管理器,我们所要操作的句柄则返回给varable

        @contextmanager

        def some_generator(<arguments>):

            <setup>

            try:

                yield <value>

            finally:

                <cleanup>


    This makes this:


        with some_generator(<arguments>) as <variable>:

            <body>


    equivalent to this:


        <setup>

        try:

            <variable> = <value>

            <body>

        finally:

            <cleanup>


    """

    @wraps(func)

    def helper(*args, **kwds):

        return GeneratorContextManager(func(*args, **kwds))

    return helper



@contextmanager

def nested(*managers):

    """Combine multiple context managers into a single nested context manager.


   This function has been deprecated in favour of the multiple manager form

   of the with statement.


   The one advantage of this function over the multiple manager form of the

   with statement is that argument unpacking allows it to be

   used with a variable number of context managers as follows:


      with nested(*managers):

          do_something()


    """

    warn("With-statements now directly support multiple context managers",

         DeprecationWarning, 3)

    exits = []

    vars = []

    exc = (None, None, None)

    try:

        for mgr in managers:

            exit = mgr.__exit__

            enter = mgr.__enter__

            vars.append(enter())

            exits.append(exit)

        yield vars

    except:

        exc = sys.exc_info()

    finally:

        while exits:

            exit = exits.pop()

            try:

                if exit(*exc):

                    exc = (None, None, None)

            except:

                exc = sys.exc_info()

        if exc != (None, None, None):

            # Don't rely on sys.exc_info() still containing

            # the right information. Another exception may

            # have been raised and caught by an exit method

            raise exc[0], exc[1], exc[2]


#直接将某个句柄fd对象作为初始化参数传递

#在__enter__中返回这个句柄给as后的variable变量用于后续操作

#在离开with语句时,在__exit__中执行清理工作(例如句柄的关闭等)

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.py的实现:

class contextManager:
    def __init__(self, conn):
        self.conn = conn
    def __enter__(self):
        return self.conn.next()
    def __exit__(self, num1, num2, num3):
        try:
            self.conn.next()
        except StopIteration:
            pass
        return False
        
def wrapper(func):
    def innerwrapper():
        conncm = contextManager(func())
        return conncm
    return innerwrapper
        
@wrapper        
def conn():
    print 'start...to....connection...'
    yield
    print 'stop...connection'
    
    
with conn() as conn_cm:
    print 'do_something'

执行的结果是:

start...to....connection...
do_something
stop...connection




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值