理解Python中的With语句


Posted in Python onFebruary 02, 2015

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如何工作?

这看起来充满魔法,但不仅仅是魔法,Python对with的处理还很聪明。基本思想是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法。

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

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

#!/usr/bin/env python

# with_example01.py
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

行代码,输出如下

bash-3.2$ ./with_example01.py

In __enter__()

sample: Foo

In __exit__()

正如你看到的,

__enter__()方法被执行

__enter__()方法返回的值 - 这个例子中是"Foo",赋值给变量'sample'
执行代码块,打印变量"sample"的值为 "Foo"

__exit__()方法被调用

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

#!/usr/bin/env python

# with_example02.py


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

代码执行后:

bash-3.2$ ./with_example02.py

type: <type 'exceptions.ZeroDivisionError'>

value: integer division or modulo by zero

trace: <traceback object at 0x1004a8128>

Traceback (most recent call last):

  File "./with_example02.py", line 19, in <module>

    sample.do_somet hing()

  File "./with_example02.py", line 15, in do_something

    bar = 1/0

ZeroDivisionError: integer division or modulo by zero

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

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

示例代码可以在Github上面找到。

Python 相关文章推荐
Python读写Redis数据库操作示例
Mar 18 Python
python映射列表实例分析
Jan 26 Python
Python与shell的3种交互方式介绍
Apr 11 Python
python字典get()方法用法分析
Apr 17 Python
简单了解Python下用于监视文件系统的pyinotify包
Nov 13 Python
django框架model orM使用字典作为参数,保存数据的方法分析
Jun 24 Python
利用matplotlib实现根据实时数据动态更新图形
Dec 13 Python
Python基于yield遍历多个可迭代对象
Mar 12 Python
Python工程师必考的6个经典面试题
Jun 28 Python
Python pip安装第三方库实现过程解析
Jul 09 Python
Python编写万花尺图案实例
Jan 03 Python
判断Python中的Nonetype类型
May 25 Python
Linux环境下MySQL-python安装过程分享
Feb 02 #Python
Python中用pycurl监控http响应时间脚本分享
Feb 02 #Python
Python列表(list)常用操作方法小结
Feb 02 #Python
Python Sleep休眠函数使用简单实例
Feb 02 #Python
Python中实现从目录中过滤出指定文件类型的文件
Feb 02 #Python
Python实现二分法算法实例
Feb 02 #Python
Python标准异常和异常处理详解
Feb 02 #Python
You might like
php中使用Imagick实现图像直方图的实现代码
2011/08/30 PHP
双冒号 ::在PHP中的使用情况
2015/11/05 PHP
thinkPHP框架通过Redis实现增删改查操作的方法详解
2019/05/13 PHP
Avengerls vs KG BO3 第一场2.18
2021/03/10 DOTA
Javascript客户端脚本的设计和应用
2006/08/21 Javascript
9行javascript代码获取QQ群成员具体实现
2013/10/16 Javascript
动态添加option及createElement使用示例
2014/01/26 Javascript
jQuery的Each比JS原生for循环性能慢很多的原因
2016/07/05 Javascript
jQuery中ztree 点击文本框弹出下拉框的实例代码
2017/02/05 Javascript
详解Vue中添加过渡效果
2017/03/20 Javascript
详解打造 Vue.js 可复用组件
2017/03/24 Javascript
防止页面url缓存中ajax中post请求的处理方法
2017/10/10 Javascript
详解Js中的模块化是如何实现的
2017/10/18 Javascript
jQuery实现上下滚动公告栏详细代码
2018/11/21 jQuery
详解小程序退出页面时清除定时器
2019/04/28 Javascript
原生JS实现烟花效果
2020/03/10 Javascript
JavaScript中reduce()的5个基本用法示例
2020/07/19 Javascript
js实现碰撞检测
2021/01/29 Javascript
[01:20]DOTA2上海特级锦标赛现场采访:谁的ID最受青睐
2016/03/25 DOTA
python通过线程实现定时器timer的方法
2015/03/16 Python
Zabbix实现微信报警功能
2016/10/09 Python
Python 实现文件的全备份和差异备份详解
2016/12/27 Python
Python分支语句与循环语句应用实例分析
2019/05/07 Python
Pycharm远程调试原理及具体配置详解
2019/08/08 Python
Pandas实现DataFrame按行求百分数(比例数)
2019/12/27 Python
selenium切换标签页解决get超时问题的完整代码
2020/08/30 Python
英国体育器材进口商店:UK Sport Imports
2017/03/14 全球购物
Space NK美国站:英国高端美妆护肤商城
2017/05/22 全球购物
大学生职业生涯规划书范文
2014/01/14 职场文书
高中政治教学反思
2014/01/18 职场文书
晚会邀请函范文
2014/01/24 职场文书
员工工作表现评语
2014/04/26 职场文书
债务授权委托书范本
2014/10/17 职场文书
天下第一关导游词
2015/02/06 职场文书
Python中request的基本使用解决乱码问题
2022/04/12 Python
Win10此设备不支持接收Miracast无法投影的解决方法
2022/07/07 数码科技