上下文管理器是一个对象,它定义了进入和退出with块的行为,提供自动资源管理(文件、连接等)。通过类中的__enter__和__exit__方法实现,或者使用contextlib模块中的@contextmanager装饰器。
class FileManager: def __init__(self, filename, mode): self.filename = filename self.mode = mode self.file = None def __enter__(self): self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): if self.file: self.file.close() with FileManager('test.txt', 'w') as f: f.write('Hello')
细节: 在__exit__中正确处理异常很重要,返回True以抑制错误,并小心处理资源,以免在出错时未关闭它们。
问题: 如果在with块中发生了异常,Python会调用__exit__方法吗?错误参数是如何传递的?
答案: 是的,__exit__方法始终被调用,即使发生异常。此时,它接收异常类型、异常值和回溯。如果__exit__返回True,异常将被抑制。
class Simple: def __enter__(self): print('Enter') def __exit__(self, exc_type, exc_val, exc_tb): print('Exit') print(exc_type, exc_val) return True # 错误不会 "抛出" 外部 with Simple(): raise ValueError('boom!')
故事
__exit__——在出现异常的情况下,文件未关闭,导致文件描述符泄漏,并在处理大量文件时出现失败。故事
__exit__中返回True。这"抑制"了错误,导致无声崩溃和数据完整性问题,因为逻辑认为事务是成功的。故事
在使用contextlib模块中的@contextmanager装饰器时,忘记在yield内部处理异常,导致在代码崩溃时与套接字的连接未关闭,服务器"挂起"并且有打开的端口。