Python中实现将dataclass属性转为Optional[List[X]]的类工厂
解决方案
要实现make_lister函数,核心是通过dataclasses模块提供的工具获取原数据类的字段信息,再动态生成符合要求的新类。以下是完整实现:
from dataclasses import dataclass, fields from typing import Optional, List, Type from dataclasses_json import DataClassJsonMixin from datetime import datetime @dataclass class SrcClass(DataClassJsonMixin): number: int name: str at: datetime def make_lister(src_cls: Type) -> Type: # 获取原数据类的所有字段信息 src_fields = fields(src_cls) # 构建新类的字段字典:键为复数属性名,值为(新类型, 默认值) new_class_fields = {} for field in src_fields: # 生成复数属性名(基础规则:末尾加s,特殊词可扩展映射表) plural_field_name = field.name + "s" # 构造新类型:Optional[List[原字段类型]] new_field_type = Optional[List[field.type]] # 设置默认值为None,符合Optional类型的使用场景 new_class_fields[plural_field_name] = (new_field_type, None) # 动态创建新类,指定类名、基类(仅继承DataClassJsonMixin) lister_class = type( f"{src_cls.__name__}Lister", (DataClassJsonMixin,), new_class_fields ) # 将动态类转换为dataclass并返回 return dataclass(lister_class) # 生成目标类 SrcClassLister = make_lister(SrcClass)
关键细节说明
获取原数据类字段:
使用dataclasses.fields(src_cls)可以提取原数据类的所有字段元信息,每个字段对象包含name(属性名)、type(字段类型)等核心信息,这是实现类型转换的基础。复数属性名生成:
示例中使用简单的末尾加s规则,若需要处理特殊复数形式(如child→children),可以扩展一个映射表:plural_mapping = {"child": "children", "person": "people"} plural_field_name = plural_mapping.get(field.name, field.name + "s")类型转换:
通过Optional[List[field.type]]将原字段类型X转换为允许为空的列表类型,满足过滤规格类接收值列表的需求。动态创建类:
利用Python内置的type函数动态生成类,参数分别为:- 新类名:原类名拼接
Lister - 基类元组:仅指定
DataClassJsonMixin - 类属性:包含新字段的类型注解和默认值(
dataclass会自动识别这些属性并生成对应的字段)
- 新类名:原类名拼接
验证测试
运行以下代码可以验证生成的类是否符合预期:
# 打印类的注解信息 print(SrcClassLister.__annotations__) # 输出: # {'numbers': typing.Optional[typing.List[int]], 'names': typing.Optional[typing.List[str]], 'ats': typing.Optional[typing.List[datetime]]} # 实例化并序列化测试 filter_spec = SrcClassLister(numbers=[1, 3, 5], names=["Alice", "Charlie"]) print(filter_spec.to_json()) # 输出:{"numbers": [1, 3, 5], "names": ["Alice", "Charlie"], "ats": null}
内容的提问来源于stack exchange,提问作者probinso
相关产品推荐
相关产品推荐

