【问题标题】:populate dataclass instance from other dataclass instance从其他数据类实例填充数据类实例
【发布时间】:2021-02-05 14:04:00
【问题描述】:

我有一个场景,我有两个共享一些命令键的数据类。比方说

@dataclass
class A
key1: str = ""
key2: dict = {}
key3: Any = ""

和B类

@dataclass
class B
key1: str = ""
key3: Any = ""
key4: List = []

这两个类共享一些关键值。现在我想将 A 类中的公共键值分配给 B 类实例。

我知道的一种方法是将两个类都转换为dict 对象执行该过程并将其转换回数据类对象。但据我所知,数据类的唯一目的是有效地存储数据和管理。我相信有更好的方法。

预期的输入和输出

# State of dataclass A while B is not initialized
A(key1: "key1value", Key2: {"a": "a"}, key3: [1,2])
# State of B should be
B(key1: "key1value",key3: [1,2], key4: [])

【问题讨论】:

  • 请修正代码中的缩进。
  • 欢迎来到 SO。这不是讨论论坛或教程。请使用tour 并花时间阅读How to Ask 以及该页面上的其他链接。花点时间Python documentation。 - 尝试实施解决方案;如果遇到问题,请回来询问具体问题。
  • 值得一看SO Q&A,它处理相互继承的数据类

标签: python python-dataclasses


【解决方案1】:

你可以使用signature获取你类的所有属性,然后getattr检查键名是否相同,最后setattr更改classB的值,如下所示:

from dataclasses import dataclass, field
from inspect import signature
from typing import Any, List, Dict

def main():
  instanceA, instanceB = A("key1value", {"a": "a"}, [1,2]), B()
  attrsA, attrsB = signature(A).parameters, signature(B).parameters

  for attr in attrsA:
    if attr in attrsB:
      valueA = getattr(instanceA, attr)
      setattr(instanceB, attr, valueA)

@dataclass
class A:
  key1: str = ""
  key2: Dict[str, str] = field(default_factory=dict)
  key3: Any = ""

@dataclass
class B:
  key1: str = ""
  key3: Any = ""
  key4: List = field(default_factory=list)


if __name__ == '__main__':
  main()

分配前的实例:

A(key1='key1value', key2={'a': 'a'}, key3=[1, 2])
B(key1='', key3='', key4=[])

之后:

A(key1='key1value', key2={'a': 'a'}, key3=[1, 2])
B(key1='key1value', key3=[1, 2], key4=[])

【讨论】:

    【解决方案2】:

    如果你为你的类添加一个方法,你可以为任何类添加它,并将它用于 A 到 B 或 B 到 A。

    我看到 signature 的问题是,如果您在 init 中进行任何更改,例如将 B 类作为参数,它不再起作用了。

    from dataclasses import dataclass, field, fields
    from typing import Any
    
    @dataclass
    class A:
        key1: str = ""
        key2: dict = field(default_factory=dict)
        key3: Any = ""
    
        def set_keys(self, other):
            self_fields = list(map(lambda x: x.name,  fields(self)))
            for _field in fields(other):
                if _field.name in self_fields:
                    setattr(self, _field.name, getattr(other, _field.name))
    
    @dataclass
    class B:
        key1: str = ""
        key3: Any = ""
        key4: list = field(default_factory=list)
    
        def set_keys(self, other):
            self_fields = list(map(lambda x: x.name,  fields(self)))
            for _field in fields(other):
                if _field.name in self_fields:
                    setattr(self, _field.name, getattr(other, _field.name))
    
    a = A(key1="key1value", key3=[1, 2])
    b = B()
    
    b.set_keys(a)
    

    结果:

    A(key1='key1value', key2={'a': 'a'}, key3=[1, 2])
    B(key1='key1value', key3=[1, 2], key4=[])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-15
      • 2021-02-21
      • 1970-01-01
      • 2021-08-06
      • 2020-03-28
      • 2020-05-15
      相关资源
      最近更新 更多