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

如何为自定义非dataclass类实现__init__注解自动生成?

为非dataclass类实现带类型注解的自动__init__方法

Python的@dataclass装饰器可以自动为类生成带类型注解的__init__方法,但如果要给自定义非dataclass类实现相同功能,同时兼容mypy,完全可以用纯Python代码实现——核心思路是通过类的__annotations__属性提取类型信息,动态生成符合要求的__init__方法。

实现方案:自定义装饰器

我们可以写一个装饰器,在类定义完成后动态生成并替换类的__init__方法,同时处理类型注解和默认值,确保mypy能正确识别参数类型。

装饰器代码

from typing import TypeVar

T = TypeVar('T')

def auto_init(cls: type[T]) -> type[T]:
    # 提取类的类型注解
    field_annotations = cls.__annotations__.copy()
    # 提取带注解且有默认值的类属性
    class_defaults = {k: v for k, v in cls.__dict__.items() 
                   if not k.startswith('__') and k in field_annotations}

    # 构建__init__的参数列表
    init_params = []
    for field_name, field_type in field_annotations.items():
        # 兼容复杂类型(如list[int])的字符串表示
        type_str = repr(field_type) if not hasattr(field_type, '__name__') else field_type.__name__
        if field_name in class_defaults:
            # 带默认值的可选参数
            init_params.append(f"{field_name}: {type_str} = {repr(class_defaults[field_name])}")
        else:
            # 必填参数
            init_params.append(f"{field_name}: {type_str}")

    # 生成__init__函数代码
    init_code = f"""
def __init__(self, {', '.join(init_params)}):
    # 将参数赋值给实例属性
    for key, value in locals().items():
        if key != 'self':
            setattr(self, key, value)
"""
    # 执行代码生成函数并替换类的__init__
    namespace = {}
    exec(init_code, namespace)
    cls.__init__ = namespace['__init__']
    
    # 为__init__添加注解,确保mypy识别类型
    cls.__init__.__annotations__ = field_annotations

    return cls

使用示例

@auto_init
class A:
    number: int
    string: str 
    default_not_hinted_arg = None  # 不带注解,不会加入__init__参数

# 实例化测试
a = A(number=456, string="hello")
print(a.number)  # 输出: 456
print(a.string)  # 输出: hello
print(a.default_not_hinted_arg)  # 输出: None

# mypy会正确识别__init__参数类型,传入非int类型的number会触发类型检查报错

关键细节说明

  • 类型注解处理:通过cls.__annotations__获取类中带类型注解的字段,生成对应参数的类型标注,兼容基础类型和泛型复杂类型。
  • 默认值处理:如果带注解的字段在类中有初始赋值,会自动将其设为__init__的可选参数,和@dataclass的行为一致。
  • mypy兼容性:手动为生成的__init__方法设置__annotations__属性,解决直接使用__annotations__传递参数时的兼容性问题。
  • 非注解属性:类中不带类型注解的属性不会被加入__init__的参数列表,保持和@dataclass的行为一致,这些属性会沿用类级别的默认值。

内容的提问来源于stack exchange,提问作者Some Guy

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 07:05:10