python的上下文管理器
首先,我们来看一下with的语法格式:
withcontext_expression[astarget(s)]:with-body
with语法非常简单,我们只需要with一个表达式,然后就可以执行自定义的业务逻辑。
但是,with后面的表达式是可以任意写的吗?
答案是否定的。要想使用with语法块,with后面的的对象需要实现「上下文管理器协议」。
什么是「上下文管理器协议」?
一个类在Python中,只要实现以下方法,就实现了「上下文管理器协议」:
__enter__:在进入with语法块之前调用,返回值会赋值给with的target
__exit__:在退出with语法块时调用,一般用作异常处理
我们来看实现了这2个方法的例子:
classTestContext:def__enter__(self):print('__enter__')return1def__exit__(self,exc_type,exc_value,exc_tb):print('exc_type:%s'%exc_type)print('exc_value:%s'%exc_value)print('exc_tb:%s'%exc_tb)withTestContext()ast:print('t:%s'%t)#Output:#__enter__#t:1#exc_type:None#exc_value:None#exc_tb:None
在这个例子中,我们定义了TestContext类,它分别实现了__enter__和exit方法。
这样一来,我们就可以把TestContext当做一个「上下文管理器」来使用,也就是通过withTestContext()ast方式来执行。
从输出结果我们可以看到,具体的执行流程如下:
__enter__在进入with语句块之前被调用,这个方法的返回值赋给了with后的t变量
__exit__在执行完with语句块之后被调用
如果在with语句块内发生了异常,那么__exit__方法可以拿到关于异常的详细信息:
exc_type:异常类型
exc_value:异常对象
exc_tb:异常堆栈信息
我们来看一个发生异常的例子,观察__exit__方法拿到的异常信息是怎样的:
withTestContext()ast:#这里会发生异常a=1/0print('t:%s'%t)#Output:#__enter__#exc_type:#exc_value:integerdivisionormodulobyzero#exc_tb:#Traceback(mostrecentcalllast):#File"base.py",line16,in#a=1/0#ZeroDivisionError:integerdivisionormodulobyzero
从输出结果我们可以看到,当with语法块内发生异常后,__exit__输出了这个异常的详细信息,其中包括异常类型、异常对象、异常堆栈。
如果我们需要对异常做特殊处理,就可以在这个方法中实现自定义逻辑。
回到最开始我们讲的,使用with读取文件的例子。之所以with能够自动关闭文件资源,就是因为内置的文件对象实现了「上下文管理器协议」,这个文件对象的__enter__方法返回了文件句柄,并且在__exit__中实现了文件资源的关闭,另外,当with语法块内有异常发生时,会抛出异常给调用者。
伪代码可以这么写:
classFile:def__enter__(self):returnfile_objdef__exit__(self,exc_type,exc_value,exc_tb):#with退出时释放文件资源file_obj.close()#如果with内有异常发生抛出异常ifexc_typeisnotNone:raiseexception
这里我们小结一下,通过对with的学习,我们了解到,with非常适合用需要对于上下文处理的场景,例如操作文件、Socket,这些场景都需要在执行完业务逻辑后,释放资源。
以上内容为大家介绍了python的上下文管理器,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注IT培训机构:开发教育。http://www.baikegou.com/
鹏仔微信 15129739599 鹏仔QQ344225443 鹏仔前端 pjxi.com 共享博客 sharedbk.com
图片声明:本站部分配图来自网络。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!