python with语句_python学习27(with语句)

python学习27(with语句)

With语句

With介绍:

with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关代码统统去掉,简化try….except….finlally的处理流程。with通过__enter__方法初始化,然后在__exit__中做善后以及处理异常。所以使用with处理的对象必须有__enter__()和__exit__()这两个方法。其中__enter__()方法在语句体(with语句包裹起来的代码块)执行之前进入运

行,__exit__()方法在语句体执行完毕退出后运行。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。 这些参数在异常处理中相当有用。

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()

Sample()的 __enter__() 方法返回新创建的Sample对象,并赋值给变量sample。

执行结果:

type:

value: integer division or modulo by zero

trace:

Traceback (most recent call last):

File "ten.py", line 16, in

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异常

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)

self.handle.close()

else:

print ("error occur!") #句柄泄漏

#return True

return False #会抛出异常,中断程序的执行

with opened(r'e:\c.txt') as fp:

for line in fp.readlines():

print(line)

raise TypeError

print ("Dnoe")

Return True的执行结果

➢ opened中的__enter__() 返回的是自身的引用,这个引用可以赋值给 as 子句中的fp变量;

返回值的类型可以根据实际需要设置为不同的类型,不必是上下文管理器对象本身。

➢ __exit__() 方法中对变量exc_trackback进行检测,如果不为 None,表示发生了异常,如果

没有发生异常,缺省的返回值为 None,由于没有异常发生,__exit__() 的三个参数都为

None,上下文管理代码可以检测这种情况,做正常处理。__exit__()方法的3个参数,分别代

表异常的类型、值、以及堆栈信息。

➢ 不管是否执行过程中是否发生了异常,执行上下文管理器的 __exit__() 方法,__exit__() 方法

负责执行“清理”工作,如释放资源等。如果执行过程中没有出现异常,或者语句体中执行

了语句 break/continue/return,则以 None 作为参数调用 __exit__(None, None, None) ;

如果执行过程中出现异常,则使用 sys.exc_info 得到的异常信息为参数调用

__exit__(exc_type, exc_value, exc_traceback)

➢ 出现异常时,如果 __exit__(type, value, traceback) 返回 False,则会重新抛出异常,让

with 之外的语句逻辑来处理异常,这也是通用做法;如果返回 True,则忽略异常,不再对

异常进行处理

©著作权归作者所有:来自51CTO博客作者qq5a16e6241946e的原创作品,如需转载,请注明出处,否则将追究法律责任

noavatar_middle.gif

qq5a16e6241946e

104篇文章,11W+人气,0粉丝

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值