__init_subclass__ 在父类中能捕获子类,是因为 python 执行 class child(parent): 时自动查找基类该方法并传入新类对象;它属于类创建流程的内置回调,比 __new__ 更早、更专一,仅对直接继承生效,接收 cls 和 **kwargs,不可返回值或抛异常。

直接用 __init_subclass__ 就能拦截所有子类定义,但它不是“监控”而是“钩子”——子类一被 class 语句执行就触发,不支持动态后置监听。
为什么 __init_subclass__ 在父类里就能捕获子类?
Python 在执行 class Child(Parent): ... 时,会自动查找基类中是否存在 __init_subclass__ 方法,并把新类对象作为第一个参数传入。它本质是类创建流程的内置回调,比 __new__ 更早、更专一。
- 只对直接继承生效(
Child(Parent)触发,GrandChild(Child)不触发父类的该方法,除非Child自己也定义了) - 接收参数:
cls(新建的子类)、**kwargs(来自class语句的 keyword 参数,比如class A(B, debug=True):) - 不能返回值,也不该抛异常(否则类定义失败)
如何安全地记录或校验子类?
典型用途是注册子类或强制约束接口。关键点在于:别在钩子里做耗时操作,也别依赖尚未完成初始化的类状态。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
- 注册到全局列表或字典时,用
cls.__name__或cls本身即可,此时类体已解析完毕,方法和属性已存在 - 若需检查是否实现了某方法,用
hasattr(cls, 'required_method'),但注意:装饰器(如@abstractmethod)可能还没生效,应避免依赖inspect分析函数体 - 避免在钩子里实例化
cls()—— 此时__init__还没定义好,极易报TypeError: __init__() takes exactly 1 argument
class Plugin:
_registry = {}
def __init_subclass__(cls, name=None, **kwargs):
super().__init_subclass__(**kwargs)
# 安全:用传入的 name 或默认取类名
key = name or cls.__name__
cls._registry[key] = cls
<p>class CsvPlugin(Plugin, name="csv"): pass
class JsonPlugin(Plugin): pass</p><h1>Plugin._registry == {"csv": <class>, "JsonPlugin": <class>}</class></class>
</h1><p></p>
常见错误:混淆 __init_subclass__ 和 __subclasses__()
__subclasses__() 是运行时查询已有子类的普通方法,而 __init_subclass__ 是定义时的主动通知。两者完全不互斥,但目的不同。
- 误以为重写
__init_subclass__后调用Parent.__subclasses__()就能“看到刚定义的类”——其实可以,但这是副作用,不是设计意图 - 在
__init_subclass__里调用cls.__subclasses__()会返回空列表(子类链尚未建立完整) - 想动态“监听未来子类”?不行。Python 没有类加载事件机制,必须靠显式继承触发
真正容易被忽略的是:如果父类自己也是某个类的子类,且那个祖类也定义了 __init_subclass__,那么两个钩子都会被调用,顺序按 MRO。别假设只有你写的父类会接管逻辑。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










