slq*_*lqq 6 python python-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
Run Code Online (Sandbox Code Playgroud)
预期结果是:
example = Main()
example_d = asdict(example)
print(example_d)
{"nested": {"contacts": []}}
Run Code Online (Sandbox Code Playgroud)
我目前拥有的:
example = Main()
example_d = asdict(example)
print(example_d)
{"nested": {"name": None, "contacts": []}, surname: None}
Run Code Online (Sandbox Code Playgroud)
我知道这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)
Run Code Online (Sandbox Code Playgroud)
但它不像预期的那样工作。
_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)
Run Code Online (Sandbox Code Playgroud)
Ven*_*ath 10
您可以创建一个自定义字典工厂,删除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)
Run Code Online (Sandbox Code Playgroud)
编辑: 基于@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)
Run Code Online (Sandbox Code Playgroud)