对于系统资源如文件、数据库连接、socket而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭或断开该资源。如果不及时关闭或断开会导致出现"Toomanyopenfiles"的错误,因为系统允许打开的最大文件数量是有限的。对于数据库,如果连接数过多而没有及时关闭的话,就可能会出现"CannotconnecttoMySQLserverToomanyconnections",因为数据库连接是一种非常昂贵的资源,不可能无限制的被创建。如何规范正确关闭一个文件或断开连接就显得非常重要。
一.对可能发生异常的代码处进行try捕获,使用try/finally语句,该语句表示如果在try代码块中程序出现了异常,后续代码就不再执行,而直接跳转到except代码块。而无论如何,finally块的代码最终都会被执行。因此,只要把close放在finally代码中,文件就一定会关闭。
try:正常执行exceptException:try执行,产生异常时执行else:try执行,没有产生异常时执行。finally:无论有没有异常都执行。
写一个复制文件的代码:
执行结果:
二.用with关键字。open方法的返回值赋值给变量x,当离开with代码块的时候,系统会自动调用x.close()方法,with的作用和使用finally语句是一样的。
运行结果:
三.任何实现了__enter__()和__exit__()方法的对象都可称之为上下文管理器,上下文管理器对象就可以使用with关键字。我们可以模拟实现一个自己的文件类,让该类实现__enter__()和__exit__()方法。
运行结果:
这里需要改一下__exit__方法的参数:
执行过程:
执行withContextManager("pro_private.py","rb")时,转到__enter__方法中,执行后,把return的返回值self.cm返回给withContextManager("pro_private.py","rb")ascm中的cm。
四.contextmanager的装饰器。
通过yield将函数分割成两部分,yield之前的语句在__enter__方法中执行,yield之后的语句在__exit__方法中执行。紧跟在yield后面的值是函数的返回值。
运行结果: