Python学习笔记--with...as...语句

with 语句是什么?

有一些任务可能需要事先设置,事后做清理工作。对于这种场景,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__()方法的对象就是上下文管理器,也就是说,上下文管理器必须包含以下两个方法:
  1. __enter__(self):进入上下文管理器自动调用的方法,该方法会在with as代码块执行之前执行。如果with语句有as子句,那么该方法的返回值会被赋值给as子句后的变量;该方法可以返回多个值,因此在as子句后面也可以指定多个变量(多个变量必须由"()"括起来组成元组)
  2. __exit__(self, exc_type,exc_value, exc_traceback):退出上下文管理器自动调用的方法。该方法会在with as 代码块执行之后执行。如果with as代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为None。如果with as代码块因为异常而中止,程序也自动调用该方法,使用sys.exc_info得到的异常信息将作为调用该方法的参数

with如何工作?

紧跟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语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。

使用 with open() as.. 读写文件:

能事先需要设置,事后做清理工作。对于 使用open()函数传入文件和标示符。如果用close()函数来关闭文件,由于文件读写时都有可能产生IOError,一旦出错,后面的close()就不会调用,所以为了保证无论是否出错都能正确地关闭文件,我们可以使用try...finally或者with as来实现。

######################以上内容部分取自网络,如侵权请联系删除#####################

上一篇:java类加载子系统之类的卸载


下一篇:课堂练习题 CodeBlock