一、什么是上下文管理器?
上下文管理器类型是python的内置类型之一,上下文管理器的定义:允许用户自定义类来定义运行时上下文,在语句体被执行前进入该上下文,并在语句执行完毕时退出该上下文。
二、上下文管理器有什么用?
对于系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。例如我们经常写的
try:
f.write("hello,world")
except IOError:
print("oops error")
finally:
f.close()
这样写是没有什么问题,但python针对这种运行、退出都需要执行特定任务的场景,提供了一种更简洁的运行方式,也就是上下文管理器。
三、上下文管理器协议
上下文管理器是用户自定义的,只要一个类实现了上下文管理器协议(两个方法),就是一个上下文管理器。
contextmanager.__enter__()
进入运行时上下文并返回此对象或关联到该运行时上下文的其他对象。 此方法的返回值会绑定到使用此上下文管理器的 with 语句的 as 子句中的标识符。
contextmanager.__exit__(*exc_type*, *exc_val*, *exc_tb*)
退出运行时上下文并返回一个布尔值旗标来表明所发生的任何异常是否应当被屏蔽。 如果在执行 with 语句的语句体期间发生了异常,则参数会包含异常的类型、值以及回溯信息。 在其他情况下三个参数均为 None。
四、如何使用上下文管理器
上下文管理器要配合 with ... as ...
语句使用.
在进入 with
语句块时,会执行上下文管理器的__enter__()
,并将返回值赋值给 as
后面的对象。
当离开 with
语句块,会执行上下文管理器的__exit__(exc_type, exc_val, exc_tb)
,以确保我们想要的动作能够执行。
例如:实现一个打开文件的上下文管理器
class FileContextManager():
def__init__(self, filename, mode):
self.filename = filename
self.mode = mode
def__enter__(self):
print("entering")
self.f = open(self.filename,self.mode)
return self.f
def__exit__(self, exc_type, exc_val, exc_tb):
print("will exit")
self.f.close()
with FileContextManager('test.txt','w') as f:
f.write('hello,world')
五、contextmanager 上下文装饰器
通过 yield
将函数分割成两部分,yield
之前的语句在 __enter__
方法中执行,yield
之后的语句在 __exit__
方法中执行。紧跟在 yield
后面的值是函数的返回值(交与 as
后面的标识符)。
from contextlib import contextmanager
@contextmanager
def managed_resource(*args,**kwds):
# 打开资源
resource=open_resource(*args,**kwds)
try:
yield resource
finally:
# 释放资源
release_resource(resource)
参考:
https://docs.python.org/zh-cn/3/library/stdtypes.html#context-manager-types