理解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中的__init__ 、__new__、__call__小结
Apr 25 Python
Python实现备份文件实例
Sep 16 Python
python使用多线程不断刷新网页的方法
Mar 31 Python
Python多线程编程简单介绍
Apr 13 Python
python机器人行走步数问题的解决
Jan 29 Python
django的settings中设置中文支持的实现
Apr 28 Python
python3调用windows dos命令的例子
Aug 14 Python
tensorflow实现对张量数据的切片操作方式
Jan 19 Python
python标准库OS模块函数列表与实例全解
Mar 10 Python
pyqt5 QlistView列表显示的实现示例
Mar 24 Python
python filecmp.dircmp实现递归比对两个目录的方法
May 22 Python
谈谈python垃圾回收机制
Sep 27 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 提速工具eAccelerator 配置参数详解
2010/05/16 PHP
Thinkphp多文件上传实现方法
2014/10/31 PHP
如何使用PHP对网站验证码进行破解
2015/09/17 PHP
PHP实现的一致性哈希算法完整实例
2015/11/14 PHP
利用Fix Rss Feeds插件修复WordPress的Feed显示错误
2015/12/19 PHP
PHPTree――php快速生成无限级分类
2018/03/30 PHP
Yii框架 session 数据库存储操作方法示例
2019/11/18 PHP
讨论html与javascript在浏览器中的加载顺序问题
2013/11/27 Javascript
对比分析json及XML
2014/11/28 Javascript
cocos2dx骨骼动画Armature源码剖析(三)
2015/09/08 Javascript
详解JavaScript函数对象
2015/11/15 Javascript
谈谈我对JavaScript原型和闭包系列理解(随手笔记8)
2015/12/24 Javascript
jquery获取文档高度和窗口高度汇总
2016/01/25 Javascript
jquery实现点击弹出可放大居中及关闭的对话框(附demo源码下载)
2016/05/10 Javascript
js拼接html字符串的注意事项
2016/10/13 Javascript
分享一个精简的vue.js 图片lazyload插件实例
2017/03/13 Javascript
在pycharm中开发vue的方法步骤
2020/03/04 Javascript
Python遍历文件夹和读写文件的实现方法
2017/05/10 Python
TF-IDF与余弦相似性的应用(一) 自动提取关键词
2017/12/21 Python
scrapy-redis源码分析之发送POST请求详解
2019/05/15 Python
PyQt5根据控件Id获取控件对象的方法
2019/06/25 Python
python中的split()函数和os.path.split()函数使用详解
2019/12/21 Python
python cv2.resize函数high和width注意事项说明
2020/07/05 Python
最新PyCharm从安装到PyCharm永久激活再到PyCharm官方中文汉化详细教程
2020/11/17 Python
HTML5之消息通知的使用(Web Notification)
2018/10/30 HTML / CSS
Stylenanda中文站:韩国一线网络服装品牌
2016/12/22 全球购物
法国和欧洲海边和滑雪度假:Pierre & Vacances
2017/01/04 全球购物
上班睡觉检讨书
2014/01/09 职场文书
《音乐之都维也纳》教学反思
2014/04/16 职场文书
《美丽的南沙群岛》教学反思
2014/04/27 职场文书
党员对十八届四中全会的期盼思想汇报范文
2014/10/17 职场文书
交通事故死亡赔偿协议书
2014/12/03 职场文书
2016优秀员工先进事迹材料
2016/02/25 职场文书
React forwardRef的使用方法及注意点
2021/06/13 Javascript
Java SSH 秘钥连接mysql数据库的方法
2021/06/28 Java/Android
MySQL插入数据与查询数据
2022/03/25 MySQL