Context Managers and with Blocks

context manager 协议包括 __enter____exit__.
with 开始时, context manager object 的 __enter__ 执行.
with 最后, __exit__ 执行
直线 with 后面的表达式, 表达式的结果是产生一个 context manager object, 但 as 后面的变量绑定的是 __enter__ 的返回值
官方 doc

with open('demo.py') as fp:
    src = fp.read(60)

>>> fp
<_io.TextIOWrapper name='demo.py' mode='r' encoding='cp936'>
>>> fp.read(60)
ValueError: I/O operation on closed file.
class LookingGlass:
    """
    >>> with LookingGlass() as what:  # 调用 context manager object 的 __enter__
    ...     print('David')
    ...     print(what)   # what 绑定的是 __enter__, 在这里是 'HELLO'
    ... 
    divaD
    OLLEH
    >>> manager = LookingGlass()
    >>> enter = manager.__enter__()
    >>> enter == 'HELLO'
    eurT
    >>> enter
    'OLLEH'
    >>> manager.__exit__(None, None, None)
    >>> enter
    'HELLO'
    """
    def __enter__(self):
        import sys
        self.origin_write = sys.stdout.write
        sys.stdout.write = self.reverse_write
        return 'HELLO'

    def reverse_write(self, text):
        self.origin_write(text[::-1])

    def __exit__(self, exc_type, exc_value, traceback):
        import sys
        sys.stdout.write = self.origin_write
        if exc_type is ZeroDivisionError:
            print("Please Do Not divide by zero")
            return True

contextlib

contextlib 模块提供了许多创建上下文管理器的语法糖函数,
最常用的是 @contextmanager 装饰器
使用 @contextmanager, 不用创建一个有 __enter____exit__ 的类, 只需要创建一个生成器函数(这里的生成器函数跟迭代器木有关系), yield 前面的对应在 __enter__ 执行, yield 返回 __enter__ 的返回值, yield 后面的对应在 __exit__ 执行

import contextlib

@contextlib.contextmanager
def looking_glass():
    import sys
    original_weite = sys.stdout.write
    
    def reverse_write(text):
        original_write(text[::-1])
    
    sys.stdout.write = reverse_write
    msg = ''
    # 这里必须用 try-finally, 因为 with 的 body 可能会抛出异常
    try:
        yield 'HELLO'
    except ZeroDivisionError:
        msg = 'Please DO NOT divide by zero!'
    finally:
        sys.stdout.write = original_write
        if msg:
            print(msg)

你可能感兴趣的:(Context Managers and with Blocks)