我有一个数据类对象,其中嵌套了数据类对象。但是,当我创建主对象时,嵌套对象变成了字典:
@dataclass
class One:
f_one: int
f_two: str
@dataclass
class Two:
f_three: str
f_four: One
Two(**{'f_three': 'three', 'f_four': {'f_one': 1, 'f_two': 'two'}})
Two(f_three='three', f_four={'f_one': 1, 'f_two': 'two'})
obj = {'f_three': 'three', 'f_four': One(**{'f_one': 1, 'f_two': 'two'})}
Two(**obj)
Two(f_three='three', f_four=One(f_one=1, f_two='two'))
如您所见,只有 **obj
有效。
理想情况下,我想构建我的对象以获得如下内容:
Two(f_three='three', f_four=One(f_one=1, f_two='two'))
除了在访问对象属性时手动将嵌套字典转换为相应的数据类对象之外,还有什么方法可以实现吗?
原文由 mohi666 发布,翻译遵循 CC BY-SA 4.0 许可协议
这是一个与
dataclasses
模块本身一样复杂的请求,这意味着实现这种“嵌套字段”功能的最佳方法可能是定义一个新的装饰器,类似于@dataclass
。幸运的是,如果您不需要
__init__
方法的签名来反映字段及其默认值,就像调用dataclass
呈现的类一样,这可以简单得多:一个将调用原始dataclass
并在其生成的__init__
方法上包装一些功能的类装饰器可以用一个普通的“...(*args, **kwargs):
”函数来完成它。—换句话说,所有需要做的就是围绕生成的
__init__
方法编写一个包装器,它将检查传入“kwargs”的参数,检查是否有对应于“数据类字段类型”,如果是,在调用原始__init__
之前生成嵌套对象。也许这在英语中比在 Python 中更难拼写:请注意,除了不用担心
__init__
签名外,这也忽略了传递init=False
- 因为无论如何它都是没有意义的。(返回行中的
if
负责使用命名参数调用或直接作为装饰器调用,例如dataclass
本身)在交互式提示上:
如果您希望保留签名,我建议使用
dataclasses
模块本身中的私有辅助函数来创建一个新的__init__
。