Python with用法:自动关闭文件进程
实际上,Python提供了with语句来管理资源关闭。比如可以把打开的文件放在with语句中,这样with语句就会帮我们自动关闭文件。
with语句的语法格式如下:
withcontextexpression[astarget(s)]: with代码块
在上面的语法格式中,context_expression用于创建可自动关闭的资源。
例如,程序使用with语句来读取文件:
importcodecs #使用with语句打开文件,该语句会负责关闭文件 withcodecs.open("readlines_test.py",'r','utf-8',buffering=True)asf: forlineinf: print(line,end='')
程序也可以使用with语句来处理通过fileinput.input合并的多个文件,例如如下程序:
importfileinput #使用with语句打开文件,该语句会负责关闭文件 withfileinput.input(files=('test.txt','info.txt'))asf: forlineinf: print(line,end='')
上面两个程序都使用了with语句来管理资源,因此它们都不需要显式关闭文件。
那么,with语句的实现原理是什么?其实很简单,使用with语句管理的资源必须是一个实现上下文管理协议(contextmanageprotocol)的类,这个类的对象可被称为上下文管理器。要实现上下文管理协议,必须实现如下两个方法:
- context_manager.__enter__():进入上下文管理器自动调用的方法。该方法会在with代码块执行之前执行。如果with语句有as子句,那么该方法的返回值会被赋值给as子句后的变量;该方法可以返回多个值,因此,在as子句后面也可以指定多个变量(多个变量必须由“()”括起来组成元组)。
- context_manager.__exit__(exc_type,exc_value,exc_traceback):退出上下文管理器自动调用的方法。该方法会在with代码块执行之后执行。如果with代码块成功执行结束,程序自动调用该方法,调用该方法的三个参数都为None:如果with代码块因为异常而中止,程序也自动调用该方法,使用sys.exc_info得到的异常信息将作为调用该方法的参数。
通过上面的介绍不难发现,只要一个类实现了__enter__()和__exit__(exc_type,exc_value,exc_traceback)方法,程序就可以使用with语句来管理它;通过__exit__()方法的参数,即可判断出with代码块执行时是否遇到了异常。
换而言之,上面程序所用的文件对象、FileInput对象,其实都实现了这两个方法,因此它们都可以接受with语句的管理。
下面我们自定义一个实现上下文管理协议的类,并使用with语句来管理它:
classFkResource: def__init__(self,tag): self.tag=tag print('构造器,初始化资源:%s'%tag) #定义__enter__方法,with体之前的执行的方法 def__enter__(self): print('[__enter__%s]:'%self.tag) #该返回值将作为as子句中变量的值 return'fkit'#可以返回任意类型的值 #定义__exit__方法,with体之后的执行的方法 def__exit__(self,exc_type,exc_value,exc_traceback): print('[__exit__%s]:'%self.tag) #exc_traceback为None,代表没有异常 ifexc_tracebackisNone: print('没有异常时关闭资源') else: print('遇到异常时关闭资源') returnFalse#可以省略,默认返回None也被看做是False withFkResource('孙悟空')asdr: print(dr) print('[with代码块]没有异常') print('------------------------------') withFkResource('白骨精'): print('[with代码块]异常之前的代码') raiseException print('[with代码块]~~~~~~~~异常之后的代码')
上面程序定义了一个FkResource类,该类定义了__enter__()和__exit__()两个方法,因此该类的对象可以被with语句管理:
- 程序在执行with代码块之前,会执行__enter__()方法,并将该方法的返回值赋值给as子句后的变量。
- 程序在执行with代码块之后,会执行__exit__()方法,可以根据该方法的参数来判断with代码块是否有异常。
程序两次使用with语句管理FkResource对象。第一次,with代码块没有出现异常。第二次,with代码块出现了异常。大家可以看到,使用with语句两次对FkResource的管理略有差异(主要是在__exit()__方法中略有差异)。
运行上面的程序,可以看到如下输出结果:
构造器,初始化资源:孙悟空 [__enter__孙悟空]: fkit [with代码块]没有异常 [__exit__孙悟空]: 没有异常时关闭资源 ------------------------------ 构造器,初始化资源:白骨精 [__enter__白骨精]: [with代码块]异常之前的代码 [__exit__白骨精]: 遇到异常时关闭资源 Traceback(mostrecentcalllast): File"C:\Users\mengma\Desktop\1.py",line26,inraiseException Exception
从上面的输出结果来看,使用with语句管理资源,程序总可以在进入with代码块之前自动执行__enter__()方法,无论with代码块是否有异常,这个部分都是一样的,而且__enter__()方法的返回值被赋值给了as子句后的变量,如上面的①号输出信息所示。
对于with代码块有异常和无异常这两种情况,此时主要通过exit()方法的参数进行判断,程序可针对with代码块是否有异常分别进行处理,如程序中代码所示。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。