[Python标准库]contextlib——上下文管理器工具

[Python标准库]contextlib——上下文管理器工具
        作用:创建和处理上下文管理器的工具。
        Python 版本:2.5 及以后版本
        contextlib 模块包含一些工具,用于处理上下文管理器和 with 语句。
上下文管理器 API
        上下文管理器(context manager)要负责一个代码块中的资源,可能在进入代码块时创建资源,然后在退出代码块时清理这个资源。例如,文件支持上下文管理器 API,可以很容易地确保完成文件读写后关闭文件。
with open('/tmp/pymotw.txt', 'wt') as f:
    f.write('contents go here')
# file is automatically closed
        上下文管理器由 with 语句启用,这个 API 包括两个方法。当执行流进入 with 中的代码块时会运行 __enter__() 方法。它会返回一个对象,在这个上下文中使用。当执行流离开 with 块时,则调用这个上下文管理器的 __exit__() 方法来清理所使用的资源。
class Context(object):
    def __init__(self):
        print '__init__()'
    def __enter__(self):
        print '__enter__()'
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print '__exit__()'

with Context():
    print 'Doing work in the context'
        结合上下文管理器与 with 语句是 try:finally 块的一种更紧凑的写法,因为上下文管理器的 __exit__() 方法总会调用,即使在产生异常的情况下也是如此。
        如果在 with 语句的 as 子句中指定了名称,__enter__() 方法可以返回与这个名称相关联的任何对象。在这个例子中,Context 会返回使用了上下文的对象。
class WithinContext(object):
    def __init__(self, context):
        print 'WithinContext.__init__(%s)' % context
    def do_something(self):
        print 'WithinContext.do_something()'
    def __del__(self):
        print 'WithinContext.__del__'

class Context(object):
    def __init__(self):
        print 'Context.__init__()'
    def __enter__(self):
        print 'Context.__enter__()'
        return WithinContext(self)
    def __exit__(self, exc_type, exc_val, exc_tb):
        print 'Context.__exit__()'

with Context() as c:
    c.do_something()
        与变量 c 关联的值是 __enter__() 返回的对象,这不一定是 with 语句中创建的 Context 实例。
        __exit__() 方法接收一些参数,其中包含 with 块中产生的异常的详细信息。
class Context(object):
    def __init__(self, handle_error):
        print '__init__(%s)' % handle_error
        self.handle_error = handle_error
    def __enter__(self):
        print '__enter__()'
        return self
    def __exit__(self, exc_type, exc_val, exc_tb):
        print '__exit__()'
        print '  exc_type =', exc_type
        print '  exc_val  =', exc_val
        print '  exc_tb   =', exc_tb
        return self.handle_error

with Context(True):
    raise RuntimeError('error message handled')

print

with Context(False):
    raise RuntimeError('error message propagated')
        如果上下文管理器可以处理这个异常,__exit__() 应当返回一个 true 值来指示不需要传播这个异常。如果返回 false,就会导致 __exit__() 返回后重新抛出这个异常。
从生成器到上下文管理器
        采用传统方式创建上下文管理器,即编写一个包含 __enter__() 和 __exit__() 方法的类,这并不难。不过有些时候,对于很少的上下文来说,完全编写所有代码会是额外的负担。在这些情况下,可以使用 contextmanager() 修饰符将一个生成器函数转换为上下文管理器。
import contextlib

@contextlib.contextmanager
def make_context():
    print '  entering'
    try:
        yield()
    except RuntimeError, err:
        print '  ERROR:',err
    finally:
        print '  exiting'

print 'Normal:'
with make_context() as value:
    print '  inside with statement:', value

print '\nHandled error:'
with make_context() as value:
    raise RuntimeError('showing examle of handling an error')

print '\nUnhandled error:'
with make_context() as value:
    raise ValueError('this exception is not handled')
        生成器要初始化上下文,用 yield 生成一次值,然后清理上下文。所生成的值(如果有)会绑定到 with 语句 as 子句中的变量。with 块中的异常会在生成器中重新抛出,使之在生成器中得到处理。
嵌套上下文
        有些情况下,必须同时管理多个上下文(例如在输入和输出文件句柄之间复制数据)。为此可以嵌套 with 语句,不过,如果外部上下文并不需要单独的块,嵌套 with 语句就只会增加缩进层次而不会提供任何实际的好处。使用 nested() 可以利用一条 with 语句实现上下文嵌套。
import contextlib

@contextlib.contextmanager
def make_context(name):
    print 'entering:', name
    yield name
    print 'exiting :', name

with contextlib.nested(make_context('A'),
                       make_context('B')) as (A, B):
    print 'inside with statement:', A, B
        程序执行时会按其进入上下文的逆序离开上下文。
        在 Python 2.7 及以后版本中废弃了 nested(),因为在这些版本中的 with 语句直接支持嵌套。
import contextlib

@contextlib.contextmanager
def make_context(name):
    print 'entering:', name
    yield name
    print 'exiting :', name

with make_context('A') as A, make_context('B') as B:
    print 'inside with statement:', A, B
        每个上下文管理器与 as 子句(可选)之间用一个逗号(,)分隔。其效果类似于使用 nested(),不过避免了 nested() 不能正确实现的有关错误处理的一些边界情况。
关闭打开的句柄
        file 类直接支持上下文管理器 API,不过表示打开句柄的另外一些对象并不支持这个 API。contextlib 的标准库文档中给出的例子是一个由 urllib.urlopen() 返回的对象。还有另外一些遗留类,它们使用 close() 方法而不支持上下文管理器 API。为了确保关闭句柄,需要使用 closing() 为它创建一个上下文管理器。
import contextlib

class Door(object):
    def __init__(self):
        print '  __init__()'
    def close(self):
        print '  close()'

print 'Normal Example:'
with contextlib.closing(Door()) as door:
    print '  inside with statement'

print '\nError handling example:'
try:
    with contextlib.closing(Door()) as door:
        print '  raising from inside with statement'
        raise RuntimeError('error message')
except Exception, err:
    print '  Had an error:', err
        不论 with 块中是否有一个错误,这个句柄都会关闭。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值