用python优雅打开文件及上下文管理协议
有次面试被问到如何优雅地打开一个文件?
那就是用with语句,调用过后可以自动关闭。
但是为什么使用with语句就可以自动关闭呢,原因就是上下文管理协议。
上下文管理协议:包含方法 __enter__() 和 __exit__(),支持该协议的对象要实现这两个方法。
with open('a.txt', 'r') as a, open('b.txt', 'w') as b: b.write(a.read())
读取文件with语句的实现及其调用过程:
class ReadFile(object): def __init__(self, filename): self.file = open(filename, 'r') def __enter__(self): return self.file def __exit__(self, type, value, traceback): # type, value, traceback 分别代表错误的类型、值、追踪栈 self.file.close() # 返回 True 代表不抛出错误,否则错误会被 with 语句抛出 return True with ReadFile('test.txt') as file_read: for line in file_read.readlines(): print(line)
在调用的时候:
1、with语句先暂存了ReadFile类的__exit__方法
2、然后调用ReadFile类的__enter__方法
3、__enter__方法打开文件,并将结果返回给with语句
4、上一步的结果被传递给file_read参数
5、在with语句内对file_read参数进行操作,读取每一行
6、读取完成之后,with语句调用之前暂存的__exit__方法
7、__exit__方法关闭了文件
要注意的是,在__exit__方法内,我们关闭了文件,但最后返回True,所以错误不会被with语句抛出。否则with语句会抛出一个对应的错误。
当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。所以,还是用with语句来得保险。