8.3 让对象支持上下文管理协议
为了让一个对象兼容 语句,你需要实现 enter()
和 exit()
方法。例如,考虑如下的一个类,它能为我们创建一个网络连接:
这个类的关键特点在于它表示了一个网络连接,但是初始化的时候并不会做任何事情(比如它并没有建立一个连接)。连接的建立和关闭是使用 with
语句自动完成的,例如:
不管 with
代码块中发生什么,上面的控制流都会执行完,就算代码块中发生了异常也是一样的。事实上,exit()
方法的第三个参数包含了异常类型、异常值和追溯信息(如果有的话)。exit()
方法能自己决定怎样利用这个异常信息,或者忽略它并返回一个None值。如果 exit()
返回 True
,那么异常会被清空,就好像什么都没发生一样,with
语句后面的程序继续在正常执行。
还有一个细节问题就是 LazyConnection
类是否允许多个 with
语句来嵌套使用连接。很显然,上面的定义中一次只能允许一个socket连接,如果正在使用一个socket的时候又重复使用 语句,就会产生一个异常了。不过你可以像下面这样修改下上面的实现来解决这个问题:
在需要管理一些资源比如文件、网络连接和锁的编程环境中,使用上下文管理器是很普遍的。这些资源的一个主要特征是它们必须被手动的关闭或释放来确保程序的正确运行。例如,如果你请求了一个锁,那么你必须确保之后释放了它,否则就可能产生死锁。通过实现 enter()
和 exit()
方法并使用 with
语句可以很容易的避免这些问题,因为 exit()
方法可以让你无需担心这些了。
在 模块中有一个标准的上下文管理方案模板,可参考9.22小节。同时在12.6小节中还有一个对本节示例程序的线程安全的修改版。