来自嵌套数据类的字典

Dict from nested dataclasses

我想知道如何将嵌套数据类转换为 dict,None 字段除外。我知道 asdict() 方法存在,但我正在尝试编写类似于 asdict() 的方法,它将在 dict 创建期间忽略空值。

例如:

@dataclass
class Nested:
    name: str = None
    contacts: list = field(default_factory = list)

@dataclass
class Main:
    nested: Nested = field(default_factory = Nested)
    surname: str = None

预期结果为:

example = Main()
example_d = asdict(example)
print(example_d)

{"nested": {"contacts": []}}

我目前拥有的:

example = Main()
example_d = asdict(example)
print(example_d)

{"nested": {"name": None, "contacts": []}, surname: None}

我知道 asdict() 会忽略没有值的字段并将默认值作为默认值,但在数据类初始化期间我需要 = None

我最终重写了 asdict()_asdict_inner() 方法:

def asdict(obj, *, dict_factory=dict):
    if not _is_dataclass_instance(obj):
        raise TypeError("asdict() should be called on dataclass instances")
    return _asdict_inner(obj, dict_factory)


def _asdict_inner(obj, dict_factory):
    if _is_dataclass_instance(obj):
        result = []
        for f in fields(obj):
            value = _asdict_inner(getattr(obj, f.name), dict_factory)
            result.append((f.name, value))
        return dict_factory(result)
    elif isinstance(obj, tuple) and hasattr(obj, '_fields'):
        return type(obj)(*[_asdict_inner(v, dict_factory) for v in obj])
    elif isinstance(obj, (list, tuple)):
        return type(obj)(_asdict_inner(v, dict_factory) for v in obj)
    elif isinstance(obj, dict):
        return type(obj)((_asdict_inner(k, dict_factory),
                          _asdict_inner(v, dict_factory))
                         for k, v in obj.items() if v is not None) # <- Mine change to exclude None values and keys.
    else:
        return copy.deepcopy(obj)

但它并没有像预期的那样工作。

按要求实施 _is_dataclass_instance。它来自 dataclass 模块。

def _is_dataclass_instance(obj):
    """Returns True if obj is an instance of a dataclass."""
    return not isinstance(obj, type) and hasattr(obj, _FIELDS)

您可以创建一个自定义字典工厂来删除 None 值键并将其与 asdict() 一起使用。

class CustomDict(dict):
    def __init__(self, data):
        super().__init__(x for x in data if x[1] is not None)

example = Main()
example_d = asdict(example, dict_factory=CustomDict)

编辑: 根据@user2357112-supports-monica 的建议,这里有一个不使用自定义词典的替代方案。

def factory(data):
    return dict(x for x in data if x[1] is not None)


example = Main()
example_d = asdict(example, dict_factory=factory)