实际上,Python提供了与语句来管理资源关闭。比如可以把打开的文件放与语在句中,这与语样句就会帮我们自动关闭文件。
与语句的语法格式如下:
与上下文表达(作为目标(s)): 与代码块
在上面的语法格式中,context_expression用于创建可自动关闭的资源。
例如,程序使与语用句来读取文件:
进口编解码器 #使与语用句打开文件,该语句会负责关闭文件 与codecs.open (“readlines_test。py”、“r”、“utf - 8”,缓冲f=True): f的线: 打印(线,结束=")
程序也可以使与语用句来处理通过fileinput。输入合并的多个文件,例如如下程序:
进口fileinput #使与语用句打开文件,该语句会负责关闭文件 fileinput.input(=(“测试文件。txt”、“info.txt”) f: f的线: 打印(线,结束=")
上面两个程序都使用了与语句来管理资源,因此它们都不需要显式关闭文件。
那么,语句的实现原理是什么?其实很简单,使与语用句管理的资源必须是一个实现上下文管理协议(上下文管理协议)的类,这个类的对象可被称为上下文管理器。要实现上下文管理协议,必须实现如下两个方法:
-
<李> context_manager.__enter__():进入上下文管理器自动调用的方法。该方法会在与代码块执行之前执行。如果与语句有作为子句,那么该方法的返回值会被赋值给作为子句后的变量;该方法可以返回多个值,因此,在作为子句后面也可以指定多个变量(多个变量必须由“()”括起来组成元组)。
李> <李> context_manager。__exit__ (exc_type exc_value exc_traceback):退出上下文管理器自动调用的方法。该方法会在与代码块执行之后执行。如果与代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为没有:如果与代码块因为异常而中止,程序也自动调用该方法,使用系统。exc_info得到的异常信息将作为调用该方法的参数。李>
通过上面的介绍不难发现,只要一个类实现了__enter__()和__exit__ (exc_type、exc_value exc_traceback)方法,程序就可以使与语用句来管理它,通过__exit__()方法的参数,即可判断出的代码块执行时是否遇到了异常。
换而言之,上面程序所用的文件对象,FileInput对象,其实都实现了这两个方法,因此它们都可以接受与语句的管理。
下面我们自定义一个实现上下文管理协议的类,并使与语用句来管理它:
类FkResource: def __init__(自我、标记): 自我。标签=标签 打印(“构造器,初始化资源:% s的%标签) #定义__enter__方法,体之前的执行的方法 def __enter__(自我): 打印(' [__enter__ % s]: ' % self.tag) #该返回值将作为作为子句中变量的值 返回“fkit”#可以返回任意类型的值 #定义__exit__方法,体之后的执行的方法 def __exit__(自我、exc_type exc_value exc_traceback): 打印(' [__exit__ % s]: ' % self.tag) # exc_traceback为None,代表没有异常 如果exc_traceback没有: 打印('没有异常时关闭资源”) 其他: 打印(“遇到异常时关闭资源”) 返回False #可以省略,默认返回也没有被看做是错误的 与FkResource(“孙悟空”)博士: 打印(博士) 打印(“(与代码块)没有异常”) 打印 ('------------------------------') 与FkResource(“白骨精”): 打印(“(与代码块]异常之前的代码”) 提高异常 打印(“(与代码块)~ ~ ~ ~ ~ ~ ~ ~异常之后的代码”)
上面程序定义了一个FkResource类,该类定义了__enter__()和__exit__()两个方法,因此该类的对象可以与语被句管理:
-
<李>程序在执行与代码块之前,会执行__enter__()方法,并将该方法的返回值赋值给作为子句后的变量。李>
<李>程序在执行与代码块之后,会执行__exit__()方法,可以根据该方法的参数来判断与代码块是否有异常。李>
程序两次使与语用句管理FkResource对象。第一次,与代码块没有出现异常第。二次,与代码块出现了异常。大家可以看的到,使与语用句两次对FkResource的管理略有差异(主要是在__exit() __方法中略有差异)。