理解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多进程编程技术实例分析
Sep 16 Python
Python实现字典的key和values的交换
Aug 04 Python
Python Requests安装与简单运用
Apr 07 Python
Python实现八大排序算法
Aug 13 Python
Python基于ThreadingTCPServer创建多线程代理的方法示例
Jan 11 Python
Python简单实现网页内容抓取功能示例
Jun 07 Python
python实现人民币大写转换
Jun 20 Python
使用python的pexpect模块,实现远程免密登录的示例
Feb 14 Python
一篇文章搞定Python操作文件与目录
Aug 13 Python
Python 异常的捕获、异常的传递与主动抛出异常操作示例
Sep 23 Python
python TK库简单应用(实时显示子进程输出)
Oct 29 Python
python绘制玫瑰的实现代码
Mar 02 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,ASP.JAVA,JAVA代码格式化工具整理
2010/06/15 PHP
Smarty变量用法详解
2016/05/11 PHP
js玩一玩WSH吧
2007/02/23 Javascript
jQuery+jqmodal弹出窗口实现代码分明
2010/06/14 Javascript
JS模板实现方法
2013/04/03 Javascript
jquery对dom的操作常用方法整理
2013/06/25 Javascript
jQuery实现数秒后自动提交form的方法
2015/03/05 Javascript
JS 清除字符串数组中,重复元素的实现方法
2016/05/24 Javascript
javascript 数组的正态分布排序的问题
2016/07/31 Javascript
bootstrap网格系统使用方法解析
2017/01/13 Javascript
用js将long型数据转换成date型或datetime型的实例
2017/07/03 Javascript
vue.js使用v-if实现显示与隐藏功能示例
2018/07/06 Javascript
更优雅的微信小程序骨架屏实现详解
2019/08/07 Javascript
详解解决小程序中webview页面多层history返回问题
2019/08/20 Javascript
Vue.directive 实现元素scroll逻辑复用
2019/11/29 Javascript
Vue.js仿Select下拉框效果
2020/02/18 Javascript
Vue-cli 移动端布局和动画使用详解
2020/08/10 Javascript
angular共享依赖的解决方案分享
2020/10/15 Javascript
[02:22]2018DOTA2亚洲邀请赛VG赛前采访
2018/04/03 DOTA
教你如何在Django 1.6中正确使用 Signal
2014/06/22 Python
Python中的is和==比较两个对象的两种方法
2017/09/06 Python
解决Pycharm下面出现No R interpreter defined的问题
2018/10/29 Python
python3实现二叉树的遍历与递归算法解析(小结)
2019/07/03 Python
Python2和Python3中@abstractmethod使用方法
2020/02/04 Python
Python列表去重复项的N种方法(实例代码)
2020/05/12 Python
python selenium xpath定位操作
2020/09/01 Python
python编写实现抽奖器
2020/09/10 Python
美国女士时尚珠宝及配饰购物网站:Icing
2018/07/02 全球购物
纽约市的奢华内衣目的地:Anya Lust
2019/08/02 全球购物
GAZMAN官网:澳大利亚领先的男装品牌
2019/12/19 全球购物
这76道Java面试题及答案,祝你能成功通过面试
2016/04/16 面试题
生产车间实习自我鉴定
2013/09/23 职场文书
五型班组建设方案
2014/02/10 职场文书
2014年创先争优工作总结
2014/12/11 职场文书
养成教育工作总结
2015/08/13 职场文书
HTML怎么设置下划线?html文字加下划线方法
2021/12/06 HTML / CSS