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': ...}
要点总结
- **
__init_subclass__**在子类定义时自动调用 - 通过类定义参数传递额外配置(如
class Child(Base, arg=value)) - 比元类更简洁,无需理解
__new__/__init__ - 必须调用**
super().__init_subclass__(**kwargs)**保证继承链 - 常用于注册、验证、自动配置等场景
📝 发现内容有误?点击此处直接编辑