python __enter__ 与 __exit__的作用,以及与 with 语句的关系
转载自:http://linbo.github.io/2013/01/08/python-with/ (一直不知道博客园哪里发转载文章)
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语句是提供一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单。
python __enter__ 与 __exit__的作用,以及与 with 语句的关系的更多相关文章
- python __enter__ 与 __exit__的作用,以及与 with 语句的关系(转)
https://blog.csdn.net/xc_zhou/article/details/80810111 python __enter__ 与 __exit__的作用,以及与 with 语句的关系
- python类的__slots__属性、__del__属性、上下文(__enter__和__exit__)、
常规情况下,类的属性字典是共享的,而实例的字典是独立的.如果一个类的属性较少,但是拥有很多的实例,这些实例的属性字典会占用较多的内存空间.对这样的类来说,为了节省内存空间,可以使用__slots__类 ...
- python面向对象( item系列,__enter__ 和__exit__,__call__方法,元类)
python面向对象进阶(下) item系列 __slots__方法 __next__ 和 __iter__实现迭代器 析构函数 上下文管理协议 元类一.item系列 把对象操作属性模拟成字典的 ...
- python基础----实现上下文管理协议__enter__和__exit__
我们知道在操作文件对象的时候可以这么写 with open('a.txt') as f: '代码块' 上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明_ ...
- 上下文管理器之__enter__和__exit__
目录 前言 with as是如何工作的 自定制open方法 更多的示例 返回主目录 前言 回到顶部 有个学生在第四轮面试中被CTO问到:如何自定义实现with open的功能.然后就一脸懵逼的回来找我 ...
- 浅析python 中__name__ = '__main__' 的作用
引用http://www.jb51.net/article/51892.htm 很多新手刚开始学习python的时候经常会看到python 中__name__ = \'__main__\' 这样的代码 ...
- 【转】浅析python 中__name__ = '__main__' 的作用
原文链接:http://www.jb51.net/article/51892.htm 举例说明解释的非常清楚,应该是看到的类似博文里面最简单的一篇: 这篇文章主要介绍了python 中__name__ ...
- 002_浅析python 中__name__ = '__main__' 的作用
很多新手刚开始学习python的时候经常会看到python 中__name__ = \'__main__\' 这样的代码,可能很多新手一开始学习的时候都比较疑惑,python 中__name__ = ...
- python中的双冒号作用
Python序列切片地址可以写为[开始:结束:步长],其中的开始和结束可以省略. 1. range(n)生成[0,n)区间整数 2. 开始start省略时,默认从第0项开始 3. 结尾省略的时候,默认 ...
随机推荐
- gb2312编码提交url乱码解决
gb2312编码提交url,服务器接收时出现乱码,用System.Web.HttpUtility.UrlDecode();解码 ,还是出现乱码,困老了我好长时间,终于在google上找到了解决办法. ...
- js实现瀑布流的一种简单方法实例分享
现在说瀑布流式布局似乎有点晚了,但是每一项技术都是向着“精”和“简”的方向在不断发展,在发展到极致之前,需要一个相当漫长的过程,因此,从这个角度来说,当瀑布流被应用得越来越多的时候,反而更应该讨论它, ...
- 博客迁移到www.imyzf.com
本博客已经迁移到www.imyzf.com,本站不再更新,请谅解!
- PHP学习心得(七)——常量
常量的范围是全局的. 可以用 define() 函数来定义常量. <?php define("CONSTANT", "Hello world."); ec ...
- vim file save as
the command of vim to save as the file :w new_file_name
- 【转】oracle 针对中文字段进行排序
1)按笔画排序 select * from Table order by nlssort(columnName,'NLS_SORT=SCHINESE_STROKE_M') 2)按部首排序 select ...
- iOS 7隐藏statusbar
- (BOOL)prefersStatusBarHidden { return YES; } [[UIApplication sharedApplication] setStatusBarHidden ...
- Centos安装gnome主菜单编辑器无
首选项---主菜单-- 即是alacarte.. centos ===安装 alacarte.noarch 0:0.12.4-1.el6 即可.
- [CC150] Get all permutations of a string
Problem: Compute all permutations of a string of unique characters. 此题用循环的方式不好做,下面是一种递归的思路: 把给的字符串看成 ...
- SpringMVC与Struts2关于controller线程安全问题
SpringMVC的controller是单例的,因此springMVC的controller不是线程安全的,在使用的时候要谨慎添加成员变量,因为所有的请求都会共享这个变量. 与springMVC不同 ...