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

如何基于__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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 20:45:32