You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在所有子类__init__执行完毕后自动调用父类方法?

实现子类初始化完成后自动执行父类方法的方案

最优方案:模板方法模式

通过在父类中封装完整的初始化流程模板,让子类仅需实现自身核心逻辑,无需手动调用父类收尾方法。该方案符合面向对象设计原则,简洁易维护。

实现步骤

  1. 重构父类Formulaire:

    • 在父类__init__中整合光标设置、子类逻辑执行、光标恢复的完整流程
    • 定义空的_init_form方法作为钩子,子类重写此方法实现自身初始化逻辑
    • 使用try...finally确保无论子类逻辑是否出错,光标都会被恢复
  2. 简化子类实现:

    • 子类不再需要自定义__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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 15:01:33