shengge0 2020-02-12
如果你有时间阅读源码的习惯,可能会看到一些优秀的代码会出现带有with
关键字的语句。
对于系统资源如文件,数据库连接,socket而言,应用程序打开这些资源并执行完业务逻辑之后,必须要做的事情就是关闭该资源。
在上篇文件中,我们读写文件操作,完毕之后,关闭文件对象。调用close方法,下面来看看如何正确的关闭一个文件。
def func(): f = open("1.txt", "w") f.write("Python") f.close()
这样写有一个误区,如果在调用write方法时,出现了异常无法继续执行下面代码,资源就被该程序一直占用系统资源。
def func(): f = open("1.txt", "w") try: f.write("python") except IOError: print("oops, error") finally: f.close()
上面的程序我们使用异常进行了捕获,finally内代码执行关闭资源。如果需要学习异常的使用,请看下篇文章。
def func(): with open("1.txt", "r") as f: f.write("python")
简洁优雅的写法就是使用with关键字。with的作用和使用异常捕获try/finally语句是一样的。想了解with原理,我们必须知道上下文管理器。
任何实现了__enter__()
和__exit__()
方法的对象都可以称为上下文管理器,上下文管理器对象可以使用with关键字,文件对象也实现了上下文管理器。
自定义类实现上下文管理器,示例代码:
class File(): def __init__(self, file_name, mode): self.file_name = file_name self.mode = mode def __enter__(self): self.f = open(self.file_name, self.mode) return self.f def __exit__(self, *args): self.f.close()
enter()方法返回资源对象,这就是要打开的文件对象,exit()方法处理清除工作。因为File类实现了上下文管理器,现在就可以使用with语句了。
with File("1.txt", "w") as f: f.write("hello, python")
这样一来,系统自动调用close方法实现关闭资源。
Python提供了contextmanager的装饰器,更进一步简化了上下文管理器的实现方式,通过yield将函数分为两部分,yield之前的语句在__enter__()方法中执行,yield之后的语句在__exit__()执行。
from contextlib import contextmanger @contextmanger def my_open(path, mode): f = open(path, mode) yield f f.close()
调用:
with my_open("1.txt", "w") as f: f.write("hello, python")
本文中应用到了装饰器,异常,前面未讲到,如有需要,请看以后的文章,后续文章会讲到装饰器,下篇文章则是异常的使用。