理解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
时间: 2024-10-12 13:38:08

理解python的with语句的相关文章

转: 理解Python的With语句

Python’s with statement provides a very convenient way of dealing with the situation where you have to do a setup and teardown to make something happen. A very good example for this is the situation where you want to gain a handler to a file, read da

理解 Python 中的线程

原地址:http://blog.jobbole.com/52060/ 本文由 伯乐在线 - acmerfight 翻译自 Akshar Raaj.欢迎加入技术翻译小组.转载请参见文章末尾处的要求. 我们将会看到一些在Python中使用线程的实例和如何避免线程之间的竞争.你应当将下边的例子运行多次,以便可以注意到线程是不可预测的和线程每次运行出的不同结果.声明:从这里开始忘掉你听到过的关于GIL的东西,因为GIL不会影响到我想要展示的东西. 示例1 我们将要请求五个不同的url: 单线程 1 2

&lt;史上最强&gt;深入理解 Python 异步编程(上)

前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知道如何使用 Tornado.Twisted.Gevent 这类异步框架上,出现各种古怪的问题难以解决.而且使用了异步框架的部分同学,由于用法不对,感觉它并没牛逼到哪里去,所以很多同学做 Web 后端服务时还是采用 Flask.Django等传统的非异步框架. 从上两届 PyCon 技术大会看来,异步编程已经成了 Python 生态下一阶段的主旋律.如新兴的 Go.Rust.

深入理解 Python 异步编程(上)

http://python.jobbole.com/88291/ 前言 很多朋友对异步编程都处于"听说很强大"的认知状态.鲜有在生产项目中使用它.而使用它的同学,则大多数都停留在知道如何使用 Tornado.Twisted.Gevent 这类异步框架上,出现各种古怪的问题难以解决.而且使用了异步框架的部分同学,由于用法不对,感觉它并没牛逼到哪里去,所以很多同学做 Web 后端服务时还是采用 Flask.Django等传统的非异步框架. 从上两届 PyCon 技术大会看来,异步编程已经成

python基础(5):深入理解 python 中的赋值、引用、拷贝、作用域

在 python 中赋值语句总是建立对象的引用值,而不是复制对象.因此,python 变量更像是指针,而不是数据存储区域, 这点和大多数 OO 语言类似吧,比如 C++.java 等 ~ 1.先来看个问题吧: 在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]? >>> values = [0, 1, 2] >>> values[1] = values >>> values [0, [.

简单理解python的垃圾回收机制

关键词:垃圾回收.引用计数.分代回收.标记-清除 前言:理解python中变量的定义:抽象理解python中变量的定义过程 1.垃圾回收机制的基本组成: python采用的是以引用计数为主,以分代回收和标记清除为辅的垃圾回收机制 2.详细分析垃圾回收机制: (1)首先是引用计数: 在python中,每创建一个对象,那么python解释器会自动为其设置一个特殊的变量,这个变量称为引用计数(初始值默认是1).一旦有一个新变量指向这个对象,那么这个引用计数的值就会加1.如果引用计数的值为0.那么pyt

完全理解python深拷贝和浅拷贝

import copya = [1, 2, 3, 4, ['a', 'b']]  #原始对象b = a  #赋值,传对象的引用c = copy.copy(a)  #对象拷贝,浅拷贝d = copy.deepcopy(a)  #对象拷贝,深拷贝a.append(5)  #修改对象aa[4].append('c')  #修改对象a中的['a', 'b']数组对象print 'a = ', aprint 'b = ', bprint 'c = ', cprint 'd = ', d 输出结果:a = 

Python 的条件语句和循环语句

一.顺序结构 顺序结构是最简单的一种程序结构,程序按照语句的书写次序自上而下顺序执行. 二.分支控制语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 1.if 语句 Python中if语句的一般形式如下所示: if condition_1: statement_block_1 elif condition_2: statement_block_2 else: statement_block_3 如果 "condition_1" 为

Python While 循环语句

Python While循环语句 Python 编程中while语句用于循环执行程序,即在一些条件下,循环执行一些段程序,以处理需要重复处理的相同任务. 执行语句可以是单个语句或语句块. 判断条件可以是任何表达式,任何非零.或非空(null)的值均为true. 当判断条件假false时,循环结束. 实例: #!/usr/bin/python count = 0 while ( count < 9): print 'The count is:', count count = count +1 pr