Python上下文管理器

Context Manager

文档翻译

Python with语句支持上下文管理器定义的运行时上下文概念(runtime context). 用户定义的类实现一对方法来实现此上下文协议, 在语句体执行前进入上下文, 在与语句体结束后退出上下文

  1. contextmanager.__enter__()

    此方法用来实现进入运行时上下文,并返回此上下文关联的对象或自身对象. 此方法返回的值绑定到as语句后的标识符上.

    一个返回自身的上下文例子是: file object. file object返回自身在调用__enter__()方法后.

    with open("xxx.txt") as f:
        f.read()
    

    一个返回关联对象的例子是: decimal.localcontext().具体用法省略.

  2. contextmanager.__exit__(exc_type, exc_val, exc_tb)

    此方法用来实现退出运行时上下文, 并返回一个布尔值--用来指示如果有应该抑制的异常发生. 如果执行with语句块时发生了一个异常, 此方法的参数包含异常的类型/值/堆栈信息. 否则, 所有三个参数为None.

    此方法返回True时将导致with语句抑制异常的抛出然后继续with语句后的语句.这个语句执行完成后异常将继续向上抛出.此方法执行期间产生的异常将覆盖其他任何with语句体中的异常.

    传入此方法的异常不应该显式的重新抛出,而是, 这个方法应该返回一个False来表明此方法成功执行完成并且不会异常抛出的异常. 这用来允许上下文管理器代码容易的来检测是否此方法确实失败.

Python定义了几个上下文管理器来支持线程同步/文件立即关闭等. 除了上下文管理器协议之外, 对特定类型没有特殊的处理.

Python的生成器对象和contextlib.contextmanager装饰器提供了一个简便的方式来实现上下文管理器协议.如果一个generator functioncontextlib.contextmanager装饰器装饰, 将返回一个实现了__enter__()__exit__()方法的上下文管理器, 而不是未被装饰的生成器函数返回的迭代器.

详解

上下文管理器对象存在的目的是管理with语句, 就像迭代器存在是为了管理for语句.

with语句的目的: 简化try/finally模式.

try/finally模式: 用于保证一段代码运行完毕后执行某项操作, 即便那段代码由于异常/return语句或sys.exit()调用而终止, 也会执行指定的操作.

finally子句中的代码通常用于释放重要的资源, 或者还原临时变更的状态.

上下文管理器协议包含__enter____exit__方法.

with语句开始运行时, 会在上下文管理器对象上调用__enter__方法.

解释器调用__enter__方法时, 除了隐式的self之外,不会传入任何参数.

with语句运行结束后, 会在上下文管理器对象上调用__exit__方法, 以此扮演finally子句的角色.

传给__exit__方法的三个参数解释如下:

  • exc_type: 异常类(例如ZeroDivisionError)
  • exc_value: 异常实例. 有时会有参数传给异常构造方法, 例如错误消息. 这些参数可以使用exc_value.args获取.
  • traceback: traceback对象

不管控制流程以哪种方式退出with块, 都会在上下文管理器对象上调用__exit__方法, 而不是在__enter__方法返回的对象上调用.

with语句的as子句是可选的. 比如, 打开文件的open函数,必须加上as子句, 以便获得文件的引用.

有些上下文管理器会返回None, 因为没什么有用的对象能提供给用户.

Python标准库示例

  • sqlite3模块中用于管理事务
  • threading模块中用于维护锁/条件/信号量.
  • Decimal对象的算术运算设置环境, 参考decimal.localcontext
  • 为了测试临时给对象打补丁, 参见unittest.mock.patch函数文档.

你可能感兴趣的:(Python上下文管理器)