来自嵌套数据类的字典
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)
我想知道如何将嵌套数据类转换为 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)