python的上下文管理器

2023-12-13 3:34:42 网络知识 匿名

首先,我们来看一下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:////

发表评论: