标签:With语句
With介绍:With基本语法
With语句的基本语法格式如下:
with expression [as target]:
with_body
参数说明:
expression:是一个需要执行的表达式;
target:是一个变量或者元组,存储的是expression表达式执行返回的结果,
可选参数
With 语句是什么?
有一些任务,可能事先需要设置,事后做清理工作。对于这种场景,Python的with语句提供了一种非常方便的处理方式。一个很好的例子是文件处理,你需要获取一个文件句柄,从文件中读取数据,然后关闭文件句柄。
如果不用with语句,代码如下:
file = open("/tmp/foo.txt")
data = file.read()file.close()
file.close()
这里有两个问题:
一是可能忘记关闭文件句柄;?
二是文件读取数据发生异常,没有进行任何处理。
下面是处理异常的加强版本:
try:
f = open(‘xxx‘)
except:
print ‘fail to open‘
exit(-1)
try:
do something
except:
do something
finally:
f.close()
虽然这段代码运行良好,但是太冗长了。
这时候就是with一展身手的时候了。除了有更优雅的语法,with还可以很好的处理上下文环境产生的异常。
下面是with版本的代码:
with open("/tmp/foo.txt") as file:
data = file.read()
with的工作原理:
紧跟with后面的语句被求值后,返回对象的enter()方法被调用,这个方
法的返回值将被赋值给as关键字后面的变量;
当with后面的代码块全部被执行完之后,将调用前面返回对象的exit()方法。
代码示例:
class Sample(object):
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
执行结果:
E:\python>python ten.py
In enter()
sample: Foo
In exit()
以上代码执行过程
1.enter()方法被执行
2.enter()方法返回的值 - 这个例子中是”Foo”,赋值给变量’sample’
3.执行代码块,打印变量”sample”的值为 “Foo”
4.exit()方法被调用?
with真正强大之处是它可以处理异常。可能你已经注意到Sample类的 exit 方法有三个参数 val, type 和 trace。 这些参数在异常处理中相当有用。
c```
lass 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()
Sample()的 enter() 方法返回新创建的Sample对象,并赋值给变量sample。
执行结果:
type: <type ‘exceptions.ZeroDivisionError‘>
value: integer division or modulo by zero
trace: <traceback object at 0x00000000026A5B08>
Traceback (most recent call last):
File "ten.py", line 16, in <module>
sample.do_something()
File "ten.py", line 12, in do_something
bar = 1/0
ZeroDivisionError: integer division or modulo by zero
实际上,在with后面的代码块抛出任何异常时,exit() 方法被执行。正如例子所示,异常抛出时,与之关联的type,value和stack trace传给 exit() 方法,因此抛出的ZeroDivisionError异常被打印出来了。开发库时,清理资源,关闭文件等等操作,都可以放在 exit 方法当中。
上文说了 exit 函数可以进行部分异常的处理,如果我们不在这个函数中处理异常,他会正常抛出,这时候我们可以这样写(python 2.7及以上版本,之前的版本参考使用contextlib.nested这个库函数):
try:
with open("e:\python\222.txt") as f:
do someting
else:
do something about exception
总之,with-as表达式极大的简化了每次写finally的工作,这对保持代码的优雅性是有极大帮助的。
如果有多个项,可以这么写:
with open("e:\python\222.txt") as f1,open("e:\python\hu.txt") as f2:
content1 = f1.read()
content2 = f2.read()
print content1,content2
**自定义with异常**
从前面我们知道,with语句最关键的地方在于被求值对象必须有
__enter__()和__exit__()这两个方法,那我们就可以通过自己实现这两
示例代码:
方法来自定义with语句处理异常。
#```
coding=utf-8
class opened(object):
def __init__(self, filename):
self.handle = open(filename)
print ‘Resource: %s‘ %filename
def __enter__(self):
print ‘[Enter %s]: Allocate resource.‘ % self.handle
return self.handle #可以返回不同的对象
def __exit__(self, exc_type, exc_value, exc_trackback):
print ‘[Exit %s]: Free resource.‘ % self.handle
if exc_trackback is None:
print ‘[Exit %s]: Exited without exception.‘ % self.handle
else:
print ‘[Exit %s]: Exited with exception raised.‘ % self.handle
return False # 可以省略,缺省的None也是被看做是False
self.handle.close()
with opened(r‘e:\\python\\2.txt‘) as fp:
for line in fp.readlines():
print(line)
执行结果:
E:\python>python ten.py
Resource: e:\python\222.txt
[Enter <open file ‘e:\\python\\222.txt‘, mode ‘r‘ at 0x00000000026B8540>]: Allocate resource.
hha222
[Exit <open file ‘e:\\python\\222.txt‘, mode ‘r‘ at 0x00000000026B8540>]: Free resource.
[Exit <open file ‘e:\\python\\222.txt‘, mode ‘r‘ at 0x00000000026B8540>]: Exited without exception.
以上示例代码说明:
opened中的enter() 返回的是自身的引用,这个引用可以赋值给as 子句中的fp变量;返回值的类型可以根据实际需要设置为不同的类型,不必是上下文管理器对象本身。
exit() 方法中对变量exc_trackback进行检测,如果不为 None,表示发生了异常,返回 False 表示需要由外部代码逻辑对异常进行处理;如果没有发生异常,缺省的返回值为 None,在布尔环境中也是被看做False,但是由于没有异常发生,exit() 的三个参数都为 None,上下文管理代码可以检测这种情况,做正常处理。exit()方法的3个参数,分别代表异常的类型、值、以及堆栈信息
标签:With语句
原文地址:http://blog.51cto.com/13496943/2124662