编程Python后端开发者

在Python中,上下文管理器是如何工作的,它的用途是什么,如何通过__enter__和__exit__协议实现自己的上下文管理器?需要注意哪些细节?

用 Hintsage AI 助手通过面试

答案。

上下文管理器是一个对象,它定义了进入和退出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内部处理异常,导致在代码崩溃时与套接字的连接未关闭,服务器"挂起"并且有打开的端口。