如何将含以数据类为键的字典的dataclass转为Python字典?
解决Dataclass转字典时嵌套Dataclass作为键的转换错误
错误原因
使用dataclass_factory转换时抛出TypeError: unhashable type: 'dict',是因为默认情况下该库会把Two类实例序列化为字典,而字典是不可哈希类型,无法作为另一个字典的键(对应First.d字段的defaultdict[Two, set])。
解决方法
方法1:自定义dataclass_factory转换器
通过注册自定义序列化函数,将Two实例转为可哈希的元组,同时配置键转换器确保字典键的正确转换:
from dataclasses import dataclass, field from collections import defaultdict import dataclass_factory @dataclass(frozen=True) class Two: a: str = 'World' @dataclass class First: a: str = 'Hello' b: set[Two] = field(default_factory=lambda: set()) c: defaultdict = field(default_factory=lambda: defaultdict(set)) d: defaultdict[Two, set] = field(default_factory=lambda: defaultdict(set)) f: str = None # 创建实例 obj = First() obj.b.add(Two()) obj.d[Two('!')].add(1) # 自定义Two类的序列化函数:转为元组 def serialize_two(two: Two) -> tuple: return (two.a,) # 多字段时按dataclass字段顺序添加 # 自定义set的序列化函数:转换集合内的元素 def serialize_set(s: set) -> set: return {factory.dump(item) for item in s} # 配置转换器和键转换器 converters = { Two: serialize_two, set: serialize_set } key_converters = { Two: serialize_two } factory = dataclass_factory.Factory(converters=converters, key_converters=key_converters) result = factory.dump(obj) print(result)
转换结果示例:
{ 'a': 'Hello', 'b': {('World',)}, 'c': {}, 'd': {('!',): {1}}, 'f': None }
方法2:手动实现递归转换函数
不依赖第三方库,自己编写递归转换逻辑,完全控制每个类型的处理方式:
from dataclasses import dataclass, field, is_dataclass from collections import defaultdict @dataclass(frozen=True) class Two: a: str = 'World' @dataclass class First: a: str = 'Hello' b: set[Two] = field(default_factory=lambda: set()) c: defaultdict = field(default_factory=lambda: defaultdict(set)) d: defaultdict[Two, set] = field(default_factory=lambda: defaultdict(set)) f: str = None # 创建实例 obj = First() obj.b.add(Two()) obj.d[Two('!')].add(1) def dataclass_to_dict(obj): if is_dataclass(obj): # 特殊处理Two类:转为元组 if isinstance(obj, Two): return (obj.a,) # 其他dataclass转为字典 return { field_name: dataclass_to_dict(getattr(obj, field_name)) for field_name in obj.__dataclass_fields__ } elif isinstance(obj, set): return {dataclass_to_dict(item) for item in obj} elif isinstance(obj, (dict, defaultdict)): # 转换字典的键和值 return { dataclass_to_dict(k): dataclass_to_dict(v) for k, v in obj.items() } # 其他类型直接返回 return obj result = dataclass_to_dict(obj) print(result)
该方法更灵活,适合需要定制复杂转换逻辑的场景。
内容的提问来源于stack exchange,提问作者akseart
相关产品推荐
相关产品推荐

