如何避免子类未覆写父类方法时调用父类的高开销方法
优雅解决方案:结合上下文管理器与类方法判断
可以通过类级别方法对比判断派生类是否重写了_do_work,同时用上下文管理器确保清理操作一定会执行,完全不需要派生类做额外改动,代码逻辑也更清晰:
from contextlib import contextmanager from pathlib import Path class MyBase: def some_work(self): # 用上下文管理器包裹准备、工作、清理流程 with self._work_context() as file: if file is not None: self._do_work(file) @contextmanager def _work_context(self): file = None # 判断当前类是否重写了_do_work:对比类方法而非实例绑定方法 if self.__class__._do_work is not MyBase._do_work: file = self._do_expensive_preparation() try: yield file # 将准备好的文件传递给_do_work finally: # 仅当实际执行了准备操作,才执行清理 if file is not None: self._do_tidy_up() def _do_expensive_preparation(self) -> Path: """执行高开销准备操作""" print("执行耗时准备:创建临时文件") return Path("temp_work.txt") def _do_work(self, file: Path): """父类空实现""" pass def _do_tidy_up(self): """清理操作""" print("执行清理:删除临时文件") class DerivedA(MyBase): """未重写_do_work的派生类""" pass class DerivedB(MyBase): def _do_work(self, file: Path): """重写_do_work的派生类""" print(f"开始处理文件:{file.name}") # 这里写实际业务逻辑 # 测试验证 if __name__ == "__main__": print("=== 测试DerivedA ===") DerivedA().some_work() # 不会执行准备和清理 print("\n=== 测试DerivedB ===") DerivedB().some_work() # 会执行准备、工作、清理
方案优势
- 自动判断,无需派生类配合:通过
self.__class__._do_work is not MyBase._do_work准确判断是否重写了方法,避免了让派生类手动标记或调用准备/清理的不可靠性。 - 上下文管理器保证清理:无论
_do_work是否抛出异常,只要执行了准备操作,_do_tidy_up一定会被调用,避免资源泄漏。 - 逻辑封装,职责清晰:准备、判断、清理逻辑都封装在基类的上下文管理器中,派生类只需要专注于实现
_do_work即可,符合开闭原则。
补充说明
如果担心派生类通过多层继承间接重写_do_work,这个判断依然有效——只要当前类的_do_work不是基类的原始方法,就会触发准备流程,完全覆盖实际场景。
内容的提问来源于stack exchange,提问作者quite68
相关产品推荐
相关产品推荐

