博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
with as 如何工作
阅读量:5299 次
发布时间:2019-06-14

本文共 3362 字,大约阅读时间需要 11 分钟。

 

with如何工作?

Python对with的处理还是很机智滴.基本思想就是with所求值的对象必须有一个__enter__()方法,一个__exit__()方法

 

紧跟with后面的语句被求值后,返回对象的__enter__()方法被调用,这个方法的返回值将被赋值给as后面的变量,当with后面的代码块全部被执行完之后,将调用前面返回对象的__exit__()方法.

下面例子可以具体说明with如何工作

class Sample:    def __enter__(self):        print("in __enter__")        return "foo"  # 返回值赋值给了"sample",所以下面代码打印的foo    def __exit__(self, exc_type, exc_val, exc_tb):        print("in __exit__()")def get_sample():    return Sample()with get_sample() as sample:    print("sample", sample)

运行代码,输出如下

in __enter__sample fooin __exit__()

1,__enter__()方法被执行

2,__enter__()方法返回的值 - 这个例子中的"foo",赋值给变量"sample"

3,执行代码块,打印变量"smple"的值为"foo"

4,__exit__()方法被调用

with真正强大之处是他可以处理异常,可能你已经注意到Sample类的__exit__方法有三个参数

exc_type,exc_val,exc_tb.这些参数在异常处理中相当有用,我们开修改下代码:

class Sample:    def __enter__(self):        return self    def __exit__(self, exc_type, exc_val, exc_tb):        print("type: ", exc_type)        print("value: ", exc_val)        print("trace: ", exc_tb)    def do_something(self):        bar = 1/0        return bar + 10with Sample() as sample:    sample.do_something()

这个例子中,wilt后面的get_sample()变成了Sample().这没有任何关系.只要紧跟with后面的语句所返回的对象有__enter__()和__exit__()方法即可,此例中,Sample()的__enter__()方法返回新创建的Sample对象,并赋值给变量sample.

代码执行后:

type:  
value: division by zerotrace:
Traceback (most recent call last): File "D:/数据管理/python全栈开发13期/网络编程/day_39/队列.py", line 164, in
sample.do_something() File "D:/数据管理/python全栈开发13期/网络编程/day_39/队列.py", line 160, in do_something bar = 1/0ZeroDivisionError: division by zero

实际上,在with后面的代码块抛出任何异常时,__exit__()方法被执行.正如例子所示,异常抛出时,与之关联的type,value和trace传给__exit__()方法,因此判处的ZeroDivisionError异常被打印出来了.开发库,清理资源,关闭文件等等操作,都可以放在__exit__()方法当中.

因此,Python的with语句时提供了一个有效的机制,让代码更简练,同时在异常产生时,清理工作更简单.

 

自定义

with语句后面的对象必须要有__enter__和__exit__方法,如下:

class WithTest():    def __init__(self, name):        self.name = name    def __enter__(self):        print("This is enter function", type(self))        return self    def __exit__(self, exc_type, exc_val, exc_tb):        print("Now you are exit")    def playNow(self):        print("now i am playing")with WithTest("chenrun") as test:   # 类中的__enter__方法,将self也就是对象返回并赋值给test    print("test: ",type(test))    test.playNow()    print(test.name)
运行结果: This is enter function 
test:
now i am playingchenrunNow you are exit

自定义的类WithTest,重载了__enter__和__exit__函数,就可以实现with这样的语法了,注意在__enter__函数中,返回了self,在__exit__函数中,可以通过__exit__的返回值来指示with-block部分发生的异常时候需要reraise,如果返回false,则会reraise with block异常,如果返回ture,则就像是什么也没发生.

 

上下文管理contextlib模块对with - as的支持

contexlib模块提供了3个对象: 装饰器contextmanager,函数nested和上下文管理closing,使用这些对象,可以对已有的生成器函数或者对象进行包装,加入对上下文管理协议的支持,避免了专门编写上下文管理器来支持with语句.

以contextlib的closing来说,closing帮助实现了__enter__和__exit__方法,用户不需要自己在实现这两个方法,但时被closing封装的对象必须提供close方法.contextlib.closing类的实现代码如下:

class closing():    def __init__(self, thing):        self.thing = thing            def __enter__(self):        return self.thing        def __exit__(self, exc_type, exc_val, exc_tb):        self.thing.close()

 

还可以进行异常的监控和处理,注意后面几个参数,要跳过一个异常,只需要返回该函数True即可,下面这个代码就跳过了所有的TypeError,而让其他异常正常抛出

def __exit__(self, type, value, traceback):    return isinstance(value, TypeError)

总之,with-as表达式极大的简化了每次写finally的工作,这对保持代码优雅性有极大的帮助的.

 

 

转载于:https://www.cnblogs.com/cainingning/p/9374458.html

你可能感兴趣的文章
WPF中Image显示本地图片
查看>>
SVN版本管理
查看>>
哈希表等概率情况下查找成功和查找不成功的平均查找长度的计算
查看>>
SQL 操作结果集 -并集、差集、交集、结果集排序
查看>>
flume监控
查看>>
无法重启ssh
查看>>
Bugly热更新——初探
查看>>
ios12--简易购物车
查看>>
go17---并发
查看>>
守护线程
查看>>
VC++中使用MFC通过ADO连接数据库
查看>>
JavaScript验证注册信息
查看>>
延时加载图片
查看>>
C++库(Thrift)
查看>>
Hadoop综合大作业
查看>>
正则表达式
查看>>
C#获取执行存储过程的" 返回值"代码
查看>>
C# WinForm制作电子琴键盘
查看>>
2017系列(序):一系列佳作,喜迎2017
查看>>
Android开发——高斯模糊效果的简单实现
查看>>