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

如何将含以数据类为键的字典的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 23:10:26