有一些任务可能需要事先设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。比如说文件处理,假如你需要处理一个文件句柄,如果不用with语句:
file = open("/tmp/foo.txt") data = file.read() file.close()
这里有两个问题。一是可能忘记关闭文件句柄;二是文件读取数据发生异常,没有进行任何处理。下面是处理异常的加强版本:
file = open("/tmp/foo.txt") try: data = file.read() finally: file.close()
虽然这段代码运行良好,但是太冗长了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。使用with..as..语句操作上下文管理器,能够帮助我们自动分配并且释放资源。例如,使用with as语句操作已经打开的文件对象,无论期间是否抛出异常,都能保证with as语句执行完毕后自动关闭已经打开的文件。下面是with版本的代码:
with open("/tmp/foo.txt") as file: data = file.read()
简单的理解,同时包含__enter__()和__exit__()方法的对象就是上下文管理器,也就是说,上下文管理器必须包含以下两个方法:
紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量。当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法。
class Sample: def __enter__(self): print "In __enter__()" return "Foo" def __exit__(self, type, value, trace): print "In __exit__()" def get_sample(): return Sample() with get_sample() as sample: print "sample:", sample
运行代码,输出如下:
In __enter__() sample: Foo In __exit__()
处理异常:
class Sample: def __enter__(self): return self def __exit__(self, type, value, trace): print "type:", type print "value:", value print "trace:", trace def do_something(self): bar = 1/0 return bar + 10 with Sample() as sample: sample.do_something()
代码执行后会显示异常
实际上,在with后面的代码块抛出任何异常时,__exit__()方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给__exit__()方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在__exit__方法当中。 因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。
能事先需要设置,事后做清理工作。对于 使用open()函数传入文件和标示符。如果用close()函数来关闭文件,由于文件读写时都有可能产生IOError,一旦出错,后面的close()就不会调用,所以为了保证无论是否出错都能正确地关闭文件,我们可以使用try...finally或者with as来实现。
######################以上内容部分取自网络,如侵权请联系删除#####################