如何在所有子类__init__执行完毕后自动调用父类方法?
实现子类初始化完成后自动执行父类方法的方案
最优方案:模板方法模式
通过在父类中封装完整的初始化流程模板,让子类仅需实现自身核心逻辑,无需手动调用父类收尾方法。该方案符合面向对象设计原则,简洁易维护。
实现步骤
重构父类
Formulaire:- 在父类
__init__中整合光标设置、子类逻辑执行、光标恢复的完整流程 - 定义空的
_init_form方法作为钩子,子类重写此方法实现自身初始化逻辑 - 使用
try...finally确保无论子类逻辑是否出错,光标都会被恢复
- 在父类
简化子类实现:
- 子类不再需要自定义
__init__,仅需重写_init_form编写自身耗时操作逻辑
- 子类不再需要自定义
修改后的完整代码:
from tkinter import * class Formulaire(Frame): def __init__(self, controller): super().__init__(controller) try: self.set_busy_cursor(controller) # 调用子类的核心初始化逻辑 self._init_form(controller) finally: # 确保光标始终被恢复 self.unset_busy_cursor(controller) def _init_form(self, controller): # 子类需重写此方法,实现自身业务逻辑 pass def set_busy_cursor(self, controller): controller.config(cursor = "watch") def unset_busy_cursor(self, controller): controller.config(cursor = "") class Formulaire_ticket(Formulaire): def _init_form(self, controller): """需显示忙碌光标的长耗时数据处理""" a = 1 for i in range(100000): controller.update() a = a*2 root = Tk() root.geometry("500x500") btn = Button(root, text = "Busy", command = lambda: Formulaire_ticket(controller=root)) btn.pack() root.mainloop()
其他可选方案
方案二:元类自动包装子类__init__
元类可动态修改子类的__init__方法,在其末尾自动添加收尾逻辑,无需修改子类现有代码,但理解和调试成本较高:
from tkinter import * class FormulaireMeta(type): def __new__(cls, name, bases, attrs): original_init = attrs.get('__init__') def wrapped_init(self, controller): original_init(self, controller) # 自动调用父类收尾方法 self.unset_busy_cursor(controller) if original_init: attrs['__init__'] = wrapped_init return super().__new__(cls, name, bases, attrs) class Formulaire(Frame, metaclass=FormulaireMeta): def __init__(self, controller): super().__init__(controller) self.set_busy_cursor(controller) def set_busy_cursor(self, controller): controller.config(cursor = "watch") def unset_busy_cursor(self, controller): controller.config(cursor = "") class Formulaire_ticket(Formulaire): def __init__(self, controller): super().__init__(controller) """需显示忙碌光标的长耗时数据处理""" a = 1 for i in range(100000): controller.update() a = a*2 # 无需手动调用unset_busy_cursor
方案三:装饰器包装子类__init__
用装饰器自动为子类__init__添加收尾逻辑,但需要逐个装饰子类,适合子类数量较少的场景:
from tkinter import * def auto_unset_cursor(cls): original_init = cls.__init__ def wrapped_init(self, controller): original_init(self, controller) self.unset_busy_cursor(controller) cls.__init__ = wrapped_init return cls class Formulaire(Frame): def __init__(self, controller): super().__init__(controller) self.set_busy_cursor(controller) def set_busy_cursor(self, controller): controller.config(cursor = "watch") def unset_busy_cursor(self, controller): controller.config(cursor = "") @auto_unset_cursor class Formulaire_ticket(Formulaire): def __init__(self, controller): super().__init__(controller) """需显示忙碌光标的长耗时数据处理""" a = 1 for i in range(100000): controller.update() a = a*2
方案对比
- 模板方法模式:最简洁易维护,符合设计原则,优先推荐
- 元类方案:无需修改子类代码,但理解成本高
- 装饰器方案:灵活但需逐个装饰子类,适合小批量场景
内容的提问来源于stack exchange,提问作者d'Elbreil Clément
相关产品推荐
相关产品推荐

