上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围。一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存)。它的语法形式是with...as...
比较一下两段代码:
writer = open("test.txt", "w") try: writer.write('Hello ') writer.write('World') finally: writer.close()
with open("test.txt", "w") as writer: writer.write("Hello World!")上面两段代码作用相同,但是下面的代码是不是比上面的代码优雅多了?
open函数既能够当做一个简单的函数使用,又能够作为上下文管理器。这是因为open函数返回了一个文件类型变量,而这个文件类型实现了我们之前用到的write方法,但是想要作为上下文管理器还必须实现一些特殊的方法,我会在接下来的小节中介绍。
当一个对象被用作上下文管理器时:
__enter__ 方法将在进入代码块前被调用。
__exit__ 方法则在离开代码块之后被调用(即使在代码块中遇到了异常)。
class Test: def __enter__(self): print("进入模块") def __exit__(self,*unused): print("离开模块") with Test(): #由于我不需要调用方法,因此我没有使用as关键词 print("模块中执行的语句")
输出结果
>>> 进入模块 模块中执行的语句 离开模块 >>>
class PypixOpen: def __init__(self, filename, mode): self.filename = filename self.mode = mode def __enter__(self): self.openedFile = open(self.filename, self.mode) return self.openedFile def __exit__(self, *unused): self.openedFile.close() with PypixOpen(filename, mode) as writer: writer.write("Hello World from our new Context Manager!")
值得注意的是:
我们完全忽视了语句块内部可能出现的问题。
如果语句块内部发生了异常,__exit__方法将被调用,而异常将会被重新抛出(re-raised)。当处理文件写入操作时,大部分时间你肯定不希望隐藏这些异常,所以这是可以的。而对于不希望重新抛出的异常,我们可以让__exit__方法简单的返回True来忽略语句块中发生的所有异常(大部分情况下这都不是明智之举)。
上面代码*unused 指向exc_type, exc_value, traceback三个参数,当程序块中出现异常(exception),这三个参数用于描述异常。我们可以根据这三个参数进行相应的处理。如果正常运行结束,这三个参数都是None。
上一讲:Python菜鸟晋级04----raw_input() 与 input()的区别
下一讲:Python菜鸟晋级06----特殊属性整理