with/as
使用open打开过文件的对with/as都已经非常熟悉,其实with/as是对try/finally的一种替代方案。
当某个对象支持一种称为"环境管理协议"的协议时,就会通过环境管理器来自动执行某些善后清理工作,就像finally一样:不管中途是否发生异常,最终都会执行某些清理操作。
用法:
with expression [as var]: with_block_code
当expression返回的对象是支持环境管理协议的时候,就可以使用with。as var是可选的,如果不使用as var,expression返回对象将被丢弃,如果使用as var,就会将expression的返回对象赋值给变量var。
整个流程大致如下:先评估expression,如果支持环境管理协议,然后开始with/as语句块结构,当准备退出with语句块的时候,将执行对象中定义的善后操作。工作机制的细节见下文。
例如,open()返回的文件对象是支持环境管理协议的,所以可以用with/as来安全地打开文件:
with open(r'd:/a/b/c/a.log') as logfile: for line in logfile: print(line) ...more code here...
整个过程是先open(),然后with/as,输出每一行后将要退出with语句块的时候,环境管理器根据文件对象中定义的操作关闭文件。
它实际上等价于:
myfile = open(r'd:/a/b/c/a.log')try: for line in myfile: print(line) ...more code here...finally: myfile.close()
虽然在文件不被引用之后,垃圾回收器会自动回收这个文件对象,但是垃圾回收器的回收操作是有等待时间的。换句话说,如果不使用with/as打开文件,也不显示close()关闭文件,那么这个文件很可能会在用完之后保持空闲一段时间,然后才被垃圾回收器回收。
with/as不仅用于文件打开/关闭,锁操作也支持环境管理协议,也就是说,在有需要的时候会自动释放锁资源。
嵌套多个环境管理器
在python 3.1之后,with as支持多个环境管理器,使用逗号隔开即可。
with A() as a, B() as b: ...statements...
它等价于嵌套的with:
with A() as a: with B() as b: ...statements...
多环境管理器管理的多个对象会在with语句块中出现异常的时候,或者执行完with语句块的时候全部自动被清理(例如文件关闭操作)。
例如,打开两个文件,将它们的内容通过zip()合并在一起,并且同时关闭它们:
with open('a.file') as f1, open('b.file') as f2: for pair in zi[(f1, f2): print(pair)
自定义环境管理器
无论是文件还是锁,都是别人已经写好了环境管理器的对象。我们自己也可以写环境管理器,让它可以使用with/as,这实际上属于运算符重载的范畴。
新闻热点
疑难解答