如何使用cattrs将JSON结构化为支持额外字段的attrs类?
解决方案
原实现的问题在于绕过了cattrs的默认结构化逻辑,直接将原始字典参数传入自定义构造方法,因此cattrs提供的类型转换、嵌套类结构化等内置能力都没有生效,才会出现字段类型不符合预期的问题。
正确实现代码
import attr from cattr.preconf.json import make_converter @attr.s(auto_detect=True) class ClassWithExtras: foo: int converter = make_converter() def structure_with_extras(attribs: dict, cls): # 获取当前类已定义的所有attrs字段名 defined_field_names = attr.fields_dict(cls).keys() # 拆分已知字段和额外字段 known_attrs = {k: v for k, v in attribs.items() if k in defined_field_names} extra_attrs = {k: v for k, v in attribs.items() if k not in defined_field_names} # 调用cattrs默认逻辑处理已知字段,自动完成类型转换 instance = converter.structure(known_attrs, cls) # 挂载额外字段到实例 for k, v in extra_attrs.items(): setattr(instance, k, v) return instance # 为所有ClassWithExtras的子类注册结构钩子 converter.register_structure_hook_func( lambda cls: issubclass(cls, ClassWithExtras), structure_with_extras ) # 测试 structured = converter.structure({"foo": "2", "bar": 5}, ClassWithExtras) print(structured.foo + structured.bar) # 输出7,类型转换正常
实现逻辑说明
- 无需自定义类的
__init__方法,保留attrs自动生成的构造方法即可 - 结构化时先拆分入参字典:已在类中定义的字段交给cattrs默认逻辑处理,自动完成类型转换、校验、嵌套类结构化等原有操作
- 额外字段直接挂载到生成的实例上,既保留了cattrs的全部能力,又实现了额外字段的存储需求
- 所有继承自
ClassWithExtras的子类都会自动适配该逻辑,无需重复注册钩子
内容的提问来源于stack exchange,提问作者Murilo Cunha
相关产品推荐
相关产品推荐

