Python教程081 上下文管理器(context manager)
文章目录
上下文管理协议(context management protocol) 上下文管理器(context manager)
上下文管理协议(context management protocol):
包含enter()和exit()方法。
上下文管理器(context manager):
在with语句中使用,实现了enter()和exit()方法的对象。如果一个类实现了enter()和exit()方法,那么这个类就是一个上下文管理器对象。
例如,类A就是一个上下文管理器
|
|
with语句
with语句用于包装带有使用上下文管理器定义的方法的代码块的执行。基本语法结构如下:
|
|
with 语句的执行过程如下:
- 对上下文表达式求值以获得一个上下文管理器。
- 载入上下文管理器的exit()以便后续使用。
- 调用上下文管理器的enter()方法。
- 如果with语句中包含一个目标,来自enter() 的返回值将被赋值给它。
注意,with 语句会保证如果enter()方法返回时未发生错误,则exit()将总是被调用。 因此,如果在对目标列表赋值期间发生错误,则会将其视为在语句体内部发生的错误。 参见下面的第 6 步。 - 执行语句块。
- 调用上下文管理器的exit()方法。 如果语句体的退出是由异常导致的,则其类型、值和回溯信息将被作为参数传递给exit()。 否则的话,将提供三个 None 参数。 如果语句体的退出是由异常导致的,并且来自exit()方法的返回值为假,则该异常会被重新引发。 如果返回值为真,则该异常会被抑制,并会继续执行 with 语句之后的语句。 如果语句体由于异常以外的任何原因退出,则来自exit() 的返回值会被忽略,并会在该类退出正常的发生位置继续执行。
如果有多个,则会视作存在多个 with 语句嵌套来处理多个上下文管理器:
|
|
等价于
|
|
例如:
|
|
执行以上程序会输出如下结果:
|
|
为什么要使用上下文管理器?
可以以一种更加优雅的方式,操作(创建/获取/释放)资源,如文件操作、数据库连接。还有另外一个原因,可以以一种更加优雅的方式,处理异常。
例如,以下程序不会抛出异常。
|
|
执行以上程序会输出如下结果:
|
|
这就是上下文管理协议的一个强大之处,异常可以在exit 进行捕获并由你自己决定如何处理,是抛出呢还是在这里就解决了。在exit 里返回 True(没有return 就默认为 return False),就相当于告诉 Python解释器,这个异常我们已经捕获了,不需要再往外抛了。
exit方法必须要有这三个参数:
exc_type:异常类型
exc_val:异常值
exc_tb:异常的错误栈信息
当主逻辑代码没有报异常时,这三个参数将都为None。
理解并使用contextlib模块
Python的contextlib模块给我们提供了更方便的方式来实现一个自定义的上下文管理器。contextlib模块包含一个装饰器contextmanager和一些辅助函数,装饰器contextmanager只需要写一个生成器函数就可以代替自定义的上下文管理器,典型用法如下:
|
|
然后便可以用with语句调用contextmanage生成的上下文管理器了,with语句用法如下:
|
|
例子1:文件打开后自动管理的实现
|
|
例子2:数据库事务的处理
|
|
转载请注明本网址。