转自http://blog.kissdata.com/2014/05/23/python-with.html

With语句是什么?

有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。

如果不用with语句,代码如下:

  1. file = open("/tmp/foo.txt")
  2. data = file.read()
  3. file.close()

这里有两个问题:

  1. 一是可能忘记关闭文件句柄;
  2. 二是文件读取数据发生异常,没有进行任何处理。

下面是处理异常的加强版本:

  1. try:
  2. f = open('xxx')
  3. except:
  4. print 'fail to open'
  5. exit(-1)
  6. try:
  7. do something
  8. except:
  9. do something
  10. finally:
  11. f.close()

虽然这段代码运行良好,但是太冗长了。

这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。

下面是with版本的代码:

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

with如何工作?

  • 紧跟with后面的语句被求值后,返回对象的 __enter__() 方法被调用,这个方法的返回值将被赋值给as后面的变量。
  • 当with后面的代码块全部被执行完之后,将调用前面返回对象的 __exit__()方法。

下面例子可以具体说明with如何工作:

  1. #!/usr/bin/env python
  2. # with_example01.py
  3. class Sample:
  4. def __enter__(self):
  5. print "In __enter__()"
  6. return "Foo"
  7. def __exit__(self, type, value, trace):
  8. print "In __exit__()"
  9. def get_sample():
  10. return Sample()
  11. with get_sample() as sample:
  12. print "sample:", sample

运行代码,输出如下

  1. bash-3.2$ ./with_example01.py
  2. In __enter__()
  3. sample: Foo
  4. In __exit__()

正如你看到的: 1. __enter__()方法被执行 2. __enter__()方法返回的值 - 这个例子中是”Foo”,赋值给变量’sample’ 3. 执行代码块,打印变量”sample”的值为 “Foo” 4. __exit__()方法被调用 with真正强大之处是它可以处理异常。

可能你已经注意到Sample类的 __exit__ 方法有三个参数 val, type 和 trace。 这些参数在异常处理中相当有用。我们来改一下代码,看看具体如何工作的。

  1. #!/usr/bin/env python
  2. # with_example02.py
  3. class Sample:
  4. def __enter__(self):
  5. return self
  6. def __exit__(self, type, value, trace):
  7. print "type:", type
  8. print "value:", value
  9. print "trace:", trace
  10. def do_something(self):
  11. bar = 1/0
  12. return bar + 10
  13. with Sample() as sample:
  14. sample.do_something()

这个例子中,with后面的get_sample()变成了Sample()。这没有任何关系,只要紧跟with后面的语句所返回的对象有 __enter__() 和 __exit__() 方法即可。此例中,Sample()的 __enter__() 方法返回新创建的Sample对象,并赋值给变量sample。

代码执行后:

  1. bash-3.2$ ./with_example02.py
  2. type: <type 'exceptions.ZeroDivisionError'>
  3. value: integer division or modulo by zero
  4. trace: <traceback object at 0x1004a8128>
  5. Traceback (most recent call last):
  6. File "./with_example02.py", line 19, in <module>
  7. sample.do_something()
  8. File "./with_example02.py", line 15, in do_something
  9. bar = 1/0
  10. ZeroDivisionError: integer division or modulo by zero

实际上,在with后面的代码块抛出任何异常时,__exit__() 方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给 __exit__() 方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在 __exit__ 方法当中。

另外,__exit__ 除了用于tear things down,还可以进行异常的监控和处理,注意后几个参数。要跳过一个异常,只需要返回该函数True即可。

下面的样例代码跳过了所有的TypeError,而让其他异常正常抛出。

  1. def __exit__(self, type, value, traceback):
  2. return isinstance(value, TypeError)

上文说了 __exit__ 函数可以进行部分异常的处理,如果我们不在这个函数中处理异常,他会正常抛出,这时候我们可以这样写(python 2.7及以上版本,之前的版本参考使用contextlib.nested这个库函数):

  1. try:
  2. with open( "a.txt" ) as f :
  3. do something
  4. except xxxError:
  5. do something about exception

总之,with-as表达式极大的简化了每次写finally的工作,这对保持代码的优雅性是有极大帮助的。

如果有多个项,我们可以这么写:

  1. with open("x.txt") as f1, open('xxx.txt') as f2:
  2. do something with f1,f2

因此,Python的with语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。

python的with用法的更多相关文章

  1. Python回调函数用法实例详解

    本文实例讲述了Python回调函数用法.分享给大家供大家参考.具体分析如下: 一.百度百科上对回调函数的解释: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函 ...

  2. day01-day04总结- Python 数据类型及其用法

    Python 数据类型及其用法: 本文总结一下Python中用到的各种数据类型,以及如何使用可以使得我们的代码变得简洁. 基本结构 我们首先要看的是几乎任何语言都具有的数据类型,包括字符串.整型.浮点 ...

  3. 【Python】关于Python有意思的用法

    开一篇文章,记录关于Python有意思的用法,不断更新 1.Python树的遍历 def sum(t): tmp=0 for k in t: if not isinstance(k,list): tm ...

  4. python中xrange用法分析

    本文实例讲述了python中xrange用法.分享给大家供大家参考.具体如下: 先来看如下示例: >>> x=xrange(0,8) >>> print x xra ...

  5. 浅谈Python在信息学竞赛中的运用及Python的基本用法

    浅谈Python在信息学竞赛中的运用及Python的基本用法 前言 众所周知,Python是一种非常实用的语言.但是由于其运算时的低效和解释型编译,在信息学竞赛中并不用于完成算法程序.但正如LRJ在& ...

  6. python scapy的用法之ARP主机扫描和ARP欺骗

    python scapy的用法之ARP主机扫描和ARP欺骗 目录: 1.scapy介绍 2.安装scapy 3.scapy常用 4.ARP主机扫描 5.ARP欺骗 一.scapy介绍 scapy是一个 ...

  7. python函数的用法

    python函数的用法 目录: 1.定义.使用函数 1.函数定义:def 2.函数调用:例:myprint() 3.函数可以当作一个值赋值给一个变量 例:a=myprint()    a() 4.写r ...

  8. python 中@ 的用法【转】

    这只是我的个人理解: 在Python的函数中偶尔会看到函数定义的上一行有@functionName的修饰,当解释器读到@的这样的修饰符之后,会先解析@后的内容,直接就把@下一行的函数或者类作为@后边的 ...

  9. Python Enum 枚举 用法汇总

    Python Enum 枚举 用法汇总 import os import sys if sys.version_info.major + sys.version_info.minor * 0.1 &l ...

  10. python查看对象用法

    python查看类用法: dir(object_name)

随机推荐

  1. 测试工程师 技能要求:java编程,数据库,linux操作系统,自动化测试开发,性能测试,安全测试

    1.具有开发和测试经验,能负责带领大型项目测试 2.掌握或熟悉java编程,熟悉mysql,oracle等db,memcache,nosql等,有互联网行业从业经验 3.可撰写自动化测试工具以及搭建自 ...

  2. python 返回系统名称,系统平台,系统版本

    import platform import os print(os.name) print(platform.system()) print(platform.release())

  3. Redis为什么要把所有数据放到内存中?

    Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘.所以Redis具有快速和数据持久化的特性. 如果不将数据放到内存中,磁盘的I/O速度会严重影响redis的性能.在内 ...

  4. Java中泛型区别以及泛型擦除详解

    一.引言 复习javac的编译过程中的解语法糖的时候看见了泛型擦除中的举例,网上的资料大多比较散各针对性不一,在此做出自己的一些详细且易懂的总结. 二.泛型简介 泛型是JDK 1.5的一项新特性,一种 ...

  5. Rails 5 Test Prescriptions 第14章 Testing Exteranl Services(中断。)

    external testing strategy ✅ the service integration test✅ introduce VCR✅ Client Unit Tests ❌ Why an ...

  6. 2-7-搭建DNS服务器实现域名解析

    学习服务的方法: 了解服务的作用:名称,功能,特点 安装服务 配置文件的位置,端口 服务开启和关闭的脚本 修改配置文件(实战举例) 排错(从上到下,从内到外) -------------------- ...

  7. ZOJ-3962-数位dp

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5594             16进制下的数位dp,由于固定了位数,可以出现前 ...

  8. UVA-10570 Meeting with Aliens (枚举+贪心)

    题目大意:将一个1~n的环形排列变成升序的,最少需要几次操作?每次操作可以交换任意两个数字. 题目分析:枚举出1的位置.贪心策略:每次操作都保证至少一个数字交换到正确位置上. # include< ...

  9. Android下移植tcpflow

    tcpflow是linux平台下的开源抓包工具,它能监听网络url,获取http请求的各种数据.tcpflow可以说是tcpdump的简约版.要想将tcpflow移植到Android平台中,就需要通过 ...

  10. css样式中position和_position的区别

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA3IAAAEUCAIAAADhh5PYAAAgAElEQVR4nO3dPa/rNoLGcX6dW6UL+B ...