你的示例在最近的Python版本中按预期工作。
然而,文档 对于嵌套dataclasses
仍然完全缺失。如果有默认参数,则以下方法也适用:
from dataclasses import dataclass
@dataclass
class One:
f_one: int = 1
f_two: str = 'two'
@dataclass
class Two:
f_three: str = 'three'
f_four: One = One()
example = Two()
example
example = Two(f_three='four', f_four=One(f_one=2, f_two='three'))
example
example = Two(**{'f_three': 'five', 'f_four': One(**{'f_one': 3, 'f_two': 'four'})})
example
@dataclass
class Two:
f_three: str = '3'
f_four: One = One()
def __init__(self, d: dict):
self.f_three = d.get('f_three')
self.f_four = One(**d.get('f_four'))
d = {'f_three': 'six', 'f_four': {'f_one': 4, 'f_two': 'five'}}
example = Two(d)
example
重要的是,指向嵌套
dataclass
的类成员应该具有
dataclass
的类型,并使用其值进行初始化。您可以以这种方式嵌套任意级别的
dataclasses
。
另一种方法是简单地使用
dict
,它很容易序列化/反序列化为JSON:
example = {
'three': '3',
'four': {
'one': 1,
'two': '2',
}
}
一个从
Kaggle借鉴来的老技巧是将嵌套的
list
或
dict
解包到一个
Struct
中,该结构不是
dataclass
,以便进行点访问:
class Struct(dict):
"""Dataclass structure that inherits from dict."""
def __init__(self, **entries):
entries = {k: v for k, v in entries.items() if k != 'items'}
dict.__init__(self, entries)
self.__dict__.update(entries)
def __setattr__(self, attr, value):
self.__dict__[attr] = value
self[attr] = value
def structify(obj: Union[list,dict]) -> Struct:
"""Unpack list or dict into Struct for dot access of members."""
if isinstance(obj, list):
return [structify(obj[i]) for i in range(len(obj))]
elif isinstance(obj, dict):
return Struct(**{k: structify(v) for k, v in obj.items()})
return obj
s = structify(example)
s
s.three
s.four.one
s.four.two
你也可以创建一个TypedDict,但为什么要将字典和类的最差方面结合起来呢?对于每种其他语言都提供的基本功能,不应该需要外部库。你期望嵌套的数据类的行为类似于嵌套的C/C++结构体,但实际上它们非常不同。否则,pydantic 从解包的字典生成类型化类的界面很好。总的来说,Julia 在 @kwdef
宏中处理参数数据结构的方法更好:
@kwdef struct Foo
a::Int = 1
b::String
end
Foo(b="hi")
obj
,你的第二种方法是有效的。Two(**obj)
将给出Two(f_three='three', f_four=One(f_one=1, f_two='two'))
。 - Patrick Haugha = Two(f_three='three', f_four=One(f_one=1, f_two='two')); print(a)
- timotheecour