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

如何实现自动调用父类方法的Python装饰器?

自动调用父类对应方法的装饰器需求与实现尝试

我有一个包含通用方法的类层次结构,希望子类在执行自身方法前自动调用父类的对应方法,但根类显然没有父方法可调用。

手动在子类方法中添加super().f(...)并非难事,但有时会忘记某个类并非根类而遗漏该调用,直到追踪调用链时才发现中断问题。想知道是否存在符合需求的现成装饰器,或是优化自己实现的更好方式。

第一次尝试的实现

def extend_super(orig_method):
  def decorated(*args, **kwargs):
    if len(args) >= 1:
      selfarg = args[0]
      selfarg_qualname = selfarg.__class__.__qualname__
      expect_qualname = f"{selfarg_qualname}.{orig_method.__name__}"
      if expect_qualname == orig_method.__qualname__:
        try:
          super_method = getattr(super(type(selfarg), selfarg), orig_method.__name__)
          super_method.__func__(*args, **kwargs)
        except AttributeError:
          pass
    return orig_method(*args, **kwargs)
  return decorated

该实现可以正常工作:会调用父类方法,在根类处停止,甚至能兼容错误装饰普通函数。但它依赖字符串操作,显得较为笨拙。


编辑1:优化性能——缓存父类方法

原本希望将查找父类方法的开销移出函数调用过程,尝试通过gc获取装饰器所传入函数的所有引用列表,但列表中并无类的引用——因为装饰器总是在类创建前被调用,此时尚不存在可查找的类。

参考了统计函数调用次数的装饰器思路(通过在被装饰函数上添加字段存储数据),设想装饰器可在首次调用时查找父类方法并保存,后续调用直接使用已保存的方法以提升效率,实现代码如下:

def extend_super(orig_method):
  def decorated(*args, **kwargs):
    if not decorated.checked_super_method:
      decorated.checked_super_method = True
      if len(args) >= 1:
        selfarg = args[0]
        selfarg_qualname = selfarg.__class__.__qualname__
        expect_qualname = f"{selfarg_qualname}.{orig_method.__name__}"
        if expect_qualname == orig_method.__qualname__:
          super_class = super(type(selfarg), selfarg)
          try:
            decorated.super_method = getattr(super_class, orig_method.__name__)
          except AttributeError:
            pass

    if decorated.super_method is not None:
      decorated.super_method.__func__(*args, **kwargs)

    return orig_method(*args, **kwargs)

  decorated.checked_super_method = False
  decorated.super_method = None

  return decorated

Python支持为函数添加属性,缓存操作结果就是其典型应用场景,因此我对这个实现较为满意。


编辑2:发现实现的致命缺陷

上述实现仅在最底层子类中有效,因为self参数始终为首次调用的类实例。super()会找到上一级父类方法,但调用该方法时仍使用原始self参数,导致super()每次都找到同一层级,最终引发递归调用直至达到递归深度限制。

真正的解决方案或许需要手动遍历selfarg.__class__.__bases__列表,直至找到当前函数所属的类,或遍历至无父类(s.__class__.__bases__[0] == type),但这需要大量额外工作,而我原本只是想简化一个小问题,因此不愿投入过多精力。


内容的提问来源于stack exchange,提问作者John Bayko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 16:55:24