首页 > 编程语言 > 详细

笔记-python-lib-contextlib

时间:2019-03-07 14:13:15      阅读:148      评论:0      收藏:0      [点我收藏+]

笔记-python-lib-contextlib

 

1.      contextlib

with 语句很好用,但不想每次都写__enter_-和__exit__方法;

 

py标准库也为此提供了工具模块contextlib

模块提供的功能有很多,重点说一下contextmanager

 

2.      contextmanager

它提供了一个简单的上下文环境

简单使用:

from contextlib import contextmanager

 

@contextmanager

def make_open_context(filename, mode):

    fp = open(filename, mode)

    try:

        yield fp

    finally:

        fp.close()

 

with make_open_context(‘i002.txt‘,‘a‘) as fi:

    fi.write(‘hello ‘)

 

不用创建类和写__enter__,__exit__方法。

 

2.1.    代码释义

def contextmanager(func):

    """@contextmanager decorator.

 

    Typical usage:

 

        @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是一个装饰器函数,去掉注释,实际上是返回一个中间函数helper,helper返回的则是一个上下文管理器,具体的实现可以看下代码。

 

2.2.    _GeneratorContextManager(func, args, kwds)

前序准备工作非常简单,主要是后续清理代码比较多。

 

    def __enter__(self):

        try:

            return next(self.gen)

        except StopIteration:

            raise RuntimeError("generator didn‘t yield") from None

 

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

        if type is None:

            try:

                next(self.gen)

            except StopIteration:

                return False

            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)

            except StopIteration as exc:

                # Suppress StopIteration *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 RuntimeError as exc:

                # Don‘t re-raise the passed in exception. (issue27122)

                if exc is value:

                    return False

                # Likewise, avoid suppressing if a StopIteration exception

                # was passed to throw() and later wrapped into a RuntimeError

                # (see PEP 479).

                if type is StopIteration and exc.__cause__ is value:

                    return False

                raise

            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 value:

                    return False

                raise

            raise RuntimeError("generator didn‘t stop after throw()")

 

 

3.      参考文档

参考文档:https://docs.python.org/3/library/contextlib.html?highlight=contextlib#module-contextlib

 

笔记-python-lib-contextlib

原文:https://www.cnblogs.com/wodeboke-y/p/10489194.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!