zoukankan      html  css  js  c++  java
  • 理解python的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写法, 除了拥有更优雅的语法, 还能够处理异常. 下面是上面代码的with写法:

    with open("/tmp/foo.txt") as file:
        data = file.read()

    它是怎么工作的呢?

      基本思想是with关键字后面的语句生成的对象必须实现两个方法, __enter__()和__exit__()方法. with关键字后面的语句被求值后, 返回对象的__enter__()方法被调用, 这个方法的返回值被赋值为as关键字后面的变量. 当with语句后面的代码全部执行完之后, 将调用前面返回对象的__exit__()对象. 下面这个例子可以说明with语句如何工作:

    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__()

    正如你所看到的,

    1. __enter__()方法被执行

    2. __enter__()方法返回的值(这里是"foo")被赋值给变量sample

    3. 执行with语句后面的代码块, 打印sample变量的值

    4. __exit__()方法被执行

      with语句真正强大之处在于它可以处理异常, 你应该已经注意到了Sample类的__exit__()方法有三个参数, 分别是type, value和trace. 这三个参数在异常处理时非常有用, 我们来改一下代码, 看看到底是怎么工作的:

    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
    def get_sample():
        return Sample()
    with get_sample() as sample:
        sample.do_something()

    执行后的结果如下:

    type: <type 'exceptions.ZeroDivisionError'>
    value: integer division or modulo by zero
    trace: <traceback object at 0xb749c11c>
    Traceback (most recent call last):
      File "a.python", line 14, in <module>
        sample.do_something()
      File "a.python", line 9, in do_something
        bar = 1/0
    ZeroDivisionError: integer division or modulo by zero

    实际上, 在with语句后面的任何代码抛出异常时, __exit__()方法被执行, 即便不是因为Sample类里的方法产生的异常, 异常发生时, 与之关联的type, value和trace也会传给__exit__()方法. 因此抛出的ZeroDivisionError异常被打印出来了. 开发库时, 清理资源, 关闭文件等操作都可以放到__exit__()方法中.

    因此, python的with语句可以让代码更简练, 而且处理异常更加简单.

    原文参见

    Understanding Python's "With" Statement
  • 相关阅读:
    zabbix(三)网页操作
    zabbix(二)安装客户端
    zabbix(一)安装服务端
    python操作git
    elasticsearch之match
    elasticsearch之查询的两种方式
    Git 命令集合啦
    Django contenttype 组件
    Django 中 related_name/related_query_name 的区别
    Django中的CharField 和 FileField 主要讲FileField
  • 原文地址:https://www.cnblogs.com/iamswf/p/4703330.html
Copyright © 2011-2022 走看看