自定义可以和with一起工作的类
with语句在很多情况下都很有用,使用它可以大大简化代码。
例如我们想要读取一个文件:
2 for l in f :
3 print l
当with语句执行完之后,f对象的close成员函数会被自动调用。
天下没有免费的午餐,你想使用with语句,想知道什么时候能使用它,还需要了解这样一个事实:with语句仅能工作于支持上下文管理协议(context management protocol)的对象。
常见的支持上下文管理协议的对象有:file, threading模块中的locks, conditions,semaphores等。
关于上下文管理协议
紧跟在with关键字之后的表达式,应该返回一个对象,我们把这个对象称为上下文对象,这个对象需要有一个__enter__()方法和一个__exit__()方法。
在进入with语句块之前,python会调用上下文对象的__enter__()方法,它将完成with语句执行前的所有初始化工作。注意到with语句有一个可选的as var语句,它用以保存上下文对象。如果使用了as语句,则以__enter__()的返回值,为紧跟在as 之后的变量赋值。
当with结束时,无论它是否是正常结束,都会调用上下文对象的__exit__()方法。
__exit__()有三个参数,如果with语句没有发生异常,则此三个参数全部为None;若发生异常,这三个参数分别等于调用sys.exc_info()函数的三个返回值:异常类型,异常实例,跟踪记录(traceback)。如果想屏蔽发生的异常,那么设置__exit__()的返回值为True。
下面我们看一个简单的例子:
有一个consolecolor模块可以设置控制台的颜色,我想要实现这样的效果,使用某种颜色输出字符串后,立刻恢复到先前的颜色,于是我定义了这样一个类:
2 return ConsoleColor(color)
3
4 class ConsoleColor(object):
5 def __init__(self, color):
6 self.color = color
7 def __enter__(self):
8 self.oldcolor = consolecolor.get_color()
9 consolecolor.set_color(self.color)
10 def __exit__(self, e, v, tb):
11 consolecolor.set_color(self.oldcolor)
运行效果如下: