如何基于__annotations__实现父类为子类__init__生成参数?
实现基于类注解自动生成__init__参数的父类
要实现让父类根据子类的类注解自动生成带对应参数的__init__方法,同时让IDE能识别参数提示,核心是用**元类(metaclass)**在子类创建阶段动态生成__init__并设置方法签名,以下是具体实现:
基础实现版本
import inspect from typing import Any, Dict class ParentMeta(type): def __new__(cls, name: str, bases: tuple, namespace: Dict[str, Any]) -> type: # 收集子类的类注解 annotations = namespace.get('__annotations__', {}) # 动态生成__init__方法 def __init__(self, **kwargs): for attr, _type in annotations.items(): setattr(self, attr, kwargs[attr]) # 为__init__生成方法签名,让IDE识别参数 params = [ inspect.Parameter( name=attr, kind=inspect.Parameter.POSITIONAL_OR_KEYWORD, annotation=anno ) for attr, anno in annotations.items() ] __init__.__signature__ = inspect.Signature(parameters=params) # 将生成的__init__绑定到子类 namespace['__init__'] = __init__ return super().__new__(cls, name, bases, namespace) class Parent(metaclass=ParentMeta): pass class Child(Parent): a: int b: int c: float
支持默认值的优化版本
如果需要给子类属性设置默认值,可修改元类逻辑,收集类属性的默认值并同步到__init__参数:
import inspect from typing import Any, Dict class ParentMeta(type): def __new__(cls, name: str, bases: tuple, namespace: Dict[str, Any]) -> type: annotations = namespace.get('__annotations__', {}) # 收集属性的默认值(仅保留在注解中存在的属性) attr_defaults = {k: v for k, v in namespace.items() if k in annotations} # 生成带默认值处理的__init__ def __init__(self, **kwargs): for attr, _type in annotations.items(): # 优先使用传入参数,无则用默认值,仍无则设为None value = kwargs.get(attr, attr_defaults.get(attr, None)) setattr(self, attr, value) # 生成包含默认值的方法签名 params = [] for attr, anno in annotations.items(): param_args = { 'name': attr, 'kind': inspect.Parameter.POSITIONAL_OR_KEYWORD, 'annotation': anno } if attr in attr_defaults: param_args['default'] = attr_defaults[attr] params.append(inspect.Parameter(**param_args)) __init__.__signature__ = inspect.Signature(parameters=params) namespace['__init__'] = __init__ return super().__new__(cls, name, bases, namespace) class Parent(metaclass=ParentMeta): pass class Child(Parent): a: int b: int = 10 c: float = 3.14
关键说明
- 元类
ParentMeta在子类(如Child)定义时触发,动态生成适配子类注解的__init__方法。 - 通过手动设置
__init__.__signature__属性,让IDE(如PyCharm、VSCode)能识别参数的名称、类型和默认值,提供准确的代码提示。 - 相比直接在父类
__init__中处理,元类的方式能让子类拥有独立的、适配自身注解的__init__签名,这也是Pydantic的BaseModel实现类似功能的核心思路之一。
内容的提问来源于stack exchange,提问作者dayod
相关产品推荐
相关产品推荐

