全部学科
Python全栈
python
NodeJS全栈
nodejs
小程序首页
📅 2026-05-19 8 分钟 ✍️ juanwangdev

Python init_subclass

__init_subclass__是Python 3.6引入的钩子方法,提供比元类更简洁的子类定制方式。

基本用法

Python
class Base:
    "基类定义 __init_subclass__"

    def __init_subclass__(cls, **kwargs):
        print(f"子类 {cls.__name__} 正在初始化")
        print(f"额外参数: {kwargs}")
        super().__init_subclass__(**kwargs)  # 传递给上层

class Child(Base, option="custom", value=123):
    pass

# 输出:
# 子类 Child 正在初始化
# 额外参数: {'option': 'custom', 'value': 123}
Python
# 自动设置子类属性
class Tagged:
    def __init_subclass__(cls, tag=None, **kwargs):
        if tag:
            cls._tag = tag
        super().__init_subclass__(**kwargs)

class Animal(Tagged, tag="creature"):
    pass

class Vehicle(Tagged, tag="machine"):
    pass

print(Animal._tag)   # creature
print(Vehicle._tag)  # machine

与元类对比

Python
# 元类实现
class TagMeta(type):
    def __new__(mcs, name, bases, namespace, tag=None):
        cls = super().__new__(mcs, name, bases, namespace)
        if tag:
            cls._tag = tag
        return cls

class MetaTagged(metaclass=TagMeta, tag="meta"):
    pass

# __init_subclass__ 实现
class SimpleTagged:
    def __init_subclass__(cls, tag=None, **kwargs):
        if tag:
            cls._tag = tag
        super().__init_subclass__(**kwargs)

class SimpleTag(SimpleTagged, tag="simple"):
    pass

# __init_subclass__ 更简洁:
# - 不需要定义元类
# - 不需要理解 __new__/__init__ 区别
# - 更容易继承和组合

属性注册

Python
class RegistryBase:
    "自动注册子类"

    _registry = {}

    def __init_subclass__(cls, register=True, **kwargs):
        if register:
            RegistryBase._registry[cls.__name__] = cls
        super().__init_subclass__(**kwargs)

class HandlerA(RegistryBase):
    pass

class HandlerB(RegistryBase, register=False):
    pass

print(RegistryBase._registry)
# {'HandlerA': <class HandlerA>}
Python
# 按类型注册
class TypedRegistry:
    handlers = {}

    def __init_subclass__(cls, handler_type=None, **kwargs):
        if handler_type:
            TypedRegistry.handlers[handler_type] = cls
        super().__init_subclass__(**kwargs)

class TextHandler(TypedRegistry, handler_type='text'):
    def process(self, data):
        return data.strip()

class JsonHandler(TypedRegistry, handler_type='json'):
    def process(self, data):
        import json
        return json.loads(data)

print(TypedRegistry.handlers)
# {'text': TextHandler, 'json': JsonHandler}

接口检查

Python
class Interface:
    "强制子类实现方法"

    _required_methods = []

    def __init_subclass__(cls, **kwargs):
        # 检查必需方法
        missing = []
        for method in cls._required_methods:
            if not hasattr(cls, method):
                missing.append(method)

        if missing:
            raise NotImplementedError(
                f"{cls.__name__} 必须实现: {missing}"
            )

        super().__init_subclass__(**kwargs)

class Processor(Interface):
    _required_methods = ['process', 'validate']

class ValidProcessor(Processor):
    def process(self):
        pass

    def validate(self):
        pass

# class InvalidProcessor(Processor):
#     pass  # NotImplementedError

属性验证

Python
class Validated:
    "验证子类属性"

    _validators = {}

    def __init_subclass__(cls, **kwargs):
        # 运行验证器
        for attr_name, validator in cls._validators.items():
            if hasattr(cls, attr_name):
                value = getattr(cls, attr_name)
                if not validator(value):
                    raise ValueError(
                        f"{cls.__name__}.{attr_name} 验证失败"
                    )

        super().__init_subclass__(**kwargs)

class StrictClass(Validated):
    _validators = {
        'name': lambda x: isinstance(x, str) and len(x) > 0,
        'count': lambda x: isinstance(x, int) and x > 0,
    }

    name = "valid"
    count = 10

# name = "" 或 count = -1 会触发 ValueError

多继承处理

Python
class A:
    def __init_subclass__(cls, a_arg=None, **kwargs):
        print(f"A hook: a_arg={a_arg}")
        if a_arg:
            cls._a_arg = a_arg
        super().__init_subclass__(**kwargs)

class B:
    def __init_subclass__(cls, b_arg=None, **kwargs):
        print(f"B hook: b_arg={b_arg}")
        if b_arg:
            cls._b_arg = b_arg
        super().__init_subclass__(**kwargs)

class C(A, B, a_arg="from_a", b_arg="from_b"):
    pass

# 输出顺序:
# A hook: a_arg=from_a
# B hook: b_arg=from_b

print(C._a_arg)  # from_a
print(C._b_arg)  # from_b

注意:super().__init_subclass__(**kwargs)必须调用,否则多继承会中断链。

与描述符配合

Python
class Tracked:
    "追踪属性定义"

    def __init_subclass__(cls, track=None, **kwargs):
        if track:
            cls._tracked_attrs = track.copy()

        # 为追踪的属性添加描述符
        for attr in (track or []):
            if not hasattr(cls, f'_tracked_{attr}'):
                # 创建追踪机制
                setattr(cls, attr, TrackedDescriptor(attr))

        super().__init_subclass__(**kwargs)

class TrackedDescriptor:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, obj, owner):
        if obj is None:
            return self
        return getattr(obj, f'_tracked_{self.name}', None)

    def __set__(self, obj, value):
        old = getattr(obj, f'_tracked_{self.name}', None)
        print(f"{self.name}: {old} -> {value}")
        setattr(obj, f'_tracked_{self.name}', value)

class Data(Tracked, track=['x', 'y']):
    pass

d = Data()
d.x = 10  # 输出: x: None -> 10
d.y = 20  # 输出: y: None -> 20

类装饰器与 init_subclass

Python
# 类装饰器
def add_method(cls):
    cls.extra_method = lambda self: "extra"
    return cls

@add_method
class Decorated:
    pass

# __init_subclass__ 实现类似功能
class WithMethod:
    def __init_subclass__(cls, add_extra=False, **kwargs):
        if add_extra:
            def extra_method(self):
                return "extra"
            cls.extra_method = extra_method
        super().__init_subclass__(**kwargs)

class AutoMethod(WithMethod, add_extra=True):
    pass

# 两者效果类似,但 __init_subclass__ 支持继承链

实际应用示例

Python
# ORM 模型基类
class Model:
    "简化 ORM 基类"

    _fields = {}
    _table_name = None

    def __init_subclass__(cls, table=None, **kwargs):
        if table:
            cls._table_name = table

        # 收集字段定义
        cls._fields = {}
        for name, value in cls.__dict__.items():
            if isinstance(value, Field):
                cls._fields[name] = value

        super().__init_subclass__(**kwargs)

class Field:
    def __init__(self, type_):
        self.type = type_

class User(Model, table="users"):
    id = Field(int)
    name = Field(str)
    email = Field(str)

print(User._table_name)  # users
print(User._fields)      # {'id': ..., 'name': ..., 'email': ...}

要点总结

  1. **__init_subclass__**在子类定义时自动调用
  2. 通过类定义参数传递额外配置(如class Child(Base, arg=value)
  3. 元类更简洁,无需理解__new__/__init__
  4. 必须调用**super().__init_subclass__(**kwargs)**保证继承链
  5. 常用于注册、验证、自动配置等场景

📝 发现内容有误?点击此处直接编辑

← 上一篇 Python AST抽象语法树
下一篇 → Python __new__方法
想查看更多题目和详细解析?
小程序提供完整的题库、模拟考试和详细解析
马上就来

长按或扫描二维码,立即体验

扫码体验小程序
马上就来
使用微信扫描二维码
立即体验完整题库