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

Python中如何检测子类__init_subclass__等特殊方法是否被重写

问题解答

1. 检测技术失效的原因及其他失效场景

你所用的is身份检测逻辑,本质依赖「未重写的方法从父类继承时,访问得到的是同一个内存对象」的前提,但这个前提对类方法(@classmethod装饰的方法)完全不成立。
Python的类方法属于描述符类型,每次通过类访问类方法时,都会动态生成一个绑定了当前类的新方法对象,所以哪怕是同一个类连续两次访问同一个类方法,得到的对象身份也不一样:

>>> class A:
...     @classmethod
...     def test(cls): pass
...
>>> A.test is A.test
False

你遇到的两个特殊方法刚好都是Python隐式实现的类方法:

  • __init_subclass__ 是Python 3.6+新增的类生命周期钩子,默认隐式带有类方法语义,不需要显式加@classmethod装饰器
  • __subclasshook__ 是Python抽象基类(abc模块)定义的钩子,要求必须是类方法才能生效
    所以这两类方法访问时都会生成新的绑定对象,自然is检测会失效。除了这两个之外,所有你自己显式用@classmethod装饰的方法,都会导致这个检测逻辑失效。

注:你提供的原始检测函数存在变量名错误,if not callable(method): 中的method未定义,应该替换为subclass_method。

2. 替代检测方案

你可以避开getattr触发的描述符绑定逻辑,直接通过类的__dict__属性、遍历子类的方法解析顺序(MRO)来判断,不需要拿到绑定后的方法对象,只要判断方法的定义位置即可:

def method_has_been_overridden(superclass, subclass, method_name):
    """
    Return `True` if the method with the name `method_name`
    has been overridden in the subclass
    or an intermediate class in the method resolution order
    """
    if not issubclass(subclass, superclass):
        raise ValueError(
            "This function only makes sense if `subclass` is a subclass of `superclass`"
        )
    # 遍历子类的MRO,找第一个定义目标方法的类
    for cls in subclass.__mro__:
        if method_name in cls.__dict__:
            # 找到的定义类不是传入的父类,说明被重写
            return cls is not superclass
    # 整个继承链都没有该方法,可根据业务需求调整返回值
    return False

这个方案对普通方法、静态方法、类方法、特殊钩子方法都通用,不会触发描述符绑定逻辑,完全基于方法的定义位置判断,不受动态绑定的影响。如果仅需要判断是不是子类自身直接定义了目标方法,直接判断method_name in subclass.__dict__即可。

内容的提问来源于stack exchange,提问作者Alex Waygood

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 08:36:04