理解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可变参数用法实例分析
Apr 02 Python
Python3.5 创建文件的简单实例
Apr 26 Python
Django中使用Celery的教程详解
Aug 24 Python
django主动抛出403异常的方法详解
Jan 04 Python
Python3.4学习笔记之类型判断,异常处理,终止程序操作小结
Mar 01 Python
十行代码使用Python写一个USB病毒
Jun 21 Python
Tensorflow实现酸奶销量预测分析
Jul 19 Python
pytorch神经网络之卷积层与全连接层参数的设置方法
Aug 18 Python
python安装本地whl的实例步骤
Oct 12 Python
使用tensorflow框架在Colab上跑通猫狗识别代码
Apr 26 Python
编译 pycaffe时报错:fatal error: numpy/arrayobject.h没有那个文件或目录
Nov 29 Python
python 闭包函数详细介绍
Apr 19 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横向重复区域显示二法
2008/09/25 PHP
php实现的仿阿里巴巴实现同类产品翻页
2009/12/11 PHP
php中ltrim()、rtrim()与trim()删除字符空格实例
2014/11/25 PHP
php简单实现多语言切换的方法
2016/05/09 PHP
php编译安装php-amq扩展简明教程
2016/06/25 PHP
ThinkPHP6.0如何利用自定义验证规则规范的实现登陆
2020/12/16 PHP
JavaScript实现九九乘法表的简单实例
2016/06/07 Javascript
【经验总结】编写JavaScript代码时应遵循的14条规律
2016/06/20 Javascript
jQuery实现链接的title快速出现的方法
2017/02/20 Javascript
详解vue项目中使用token的身份验证的简单实践
2019/03/08 Javascript
Vue实现搜索结果高亮显示关键字
2019/05/28 Javascript
JS中类的静态方法,静态变量,实例方法,实例变量区别与用法实例分析
2020/03/14 Javascript
详解vue-router的导航钩子(导航守卫)
2020/11/02 Javascript
Vue实现Header渐隐渐现效果的实例代码
2020/11/05 Javascript
python常用web框架简单性能测试结果分享(包含django、flask、bottle、tornado)
2014/08/25 Python
Python实现变量数值交换及判断数组是否含有某个元素的方法
2017/09/18 Python
Python爬虫爬取一个网页上的图片地址实例代码
2018/01/16 Python
python删除某个字符
2018/03/19 Python
Python中循环引用(import)失败的解决方法
2018/04/22 Python
在Python中使用MySQL--PyMySQL的基本使用方法
2019/11/19 Python
Django 路由层URLconf的实现
2019/12/30 Python
Python模块 _winreg操作注册表
2020/02/05 Python
python3让print输出不换行的方法
2020/08/24 Python
详解Python遍历列表时删除元素的正确做法
2021/01/07 Python
CSS3实现滚动条动画效果代码分享
2016/08/03 HTML / CSS
关于老式浏览器兼容HTML5和CSS3的问题
2016/06/01 HTML / CSS
部队万能检讨书
2014/02/20 职场文书
服务质量承诺书
2014/03/27 职场文书
单位委托书范本
2014/04/04 职场文书
《大海那边》教学反思
2014/04/09 职场文书
工地安全标语
2014/06/07 职场文书
聋哑人盗窃罪辩护词
2015/05/21 职场文书
离婚被告代理词
2015/05/23 职场文书
2016年幼儿园教师政治学习心得体会
2016/01/23 职场文书
生鲜超市—未来中国最具有潜力零售业态
2019/08/02 职场文书
Python机器学习三大件之一numpy
2021/05/10 Python