Python中的上下文管理器是一个包装任意代码块的对象。它在处理资源的打开关闭、异常的处理等方面有很好的实现方法。
1. 上下文管理器的语法
假设我们需要读取一个文件中的数据,代码如下:
try:
test_file = open('test.txt', 'r')
contents = test_file.read()
finally:
test_file.close()
这是一般的写法,还有利用上下文管理器的写法,使用with关键词进入上下文管理器:
with open('test.txt', 'r') as test_file:
contents = test_file.read()
可以很明显得看出,上下文管理器的优势在于,它解决了文件关闭的问题,我们在使用资源时,若资源在用完需要及时关闭时,我们就会用到上下文管理器。
2. 内部实现逻辑
上下文管理器的实现主要是和两个方法有关:_enter_和_exit_。
本质上来讲,with语句会对其后的代码进行执行,该表达式会返回一个对象,而这个对象包含的就是上面讲的两个方法:_enter_和_exit_。
2.1 _enter_方法
_enter_方法不接受任何参数,with后的代码执行,返回对象时,该方法立即执行,如果有as变量(as子句为可选),方法的返回值会被赋给as后面的变量,一般来说,_enter_方法负责执行一些配置。
2.2 _exit_方法
_exit_方法带有3个位置参数(不包括self),一个异常类型exc_type,一个异常实例exc_val,一个回溯exc_tb。如果没有异常,这3个参数全被设置成None,如果有异常发生,则填充参数。
如果_exit_接收一个异常,就有处理这个异常的义务。如何处理这个异常,_exit_方法根据返回值有3个可选项:
• 传播异常:返回False
• 终止异常:返回True
• 抛出不同的异常:返回一个不同的异常
3. 编写上下文管理器
我们若要自行编写一个上下文管理器,则必须实现_enter_和_exit_方法,如下:
class Base_CM:
def __init__(self):
self.state = False
def __enter__(self):
self.state = True
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.state = False
这是一个简单的上下文管理器,功能只是在进入时将state属性设为True,注意,_enter_方法必须返回一个对象,可以是自身,也可以是其他的对象。我们来使用这个上下文管理器看看:
cm = Base_CM()
print(cm.state)
with cm:
print(cm.state)
print(cm.state)
输出:
False
True
False
4. 简洁写法
使用contextlib模块中的contextmanager函数,我们可以有更简洁的上下文管理器写法:
from contextlib import contextmanager
@contextmanager
def context_manager(*args):
try:
yield
except BaseException as e:
pass