从其他数据类实例填充数据类实例

populate dataclass instance from other dataclass instance

我有两个数据class,它们共享一些命令键。比方说

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

和classB

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

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

我知道的一种方法是将 class 转换为 dict 对象,然后将其转换回数据class 对象。但据我所知, dataclass 的唯一目的是有效地存储数据和管理。我相信有一些更好的方法。

预期的输入和输出

# 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: [])

您可以使用signature获取您的class的所有属性,然后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=[])

如果您向 class 添加一个方法,您可以对任何 class 执行此操作,并将其用于 A 到 B 或 B 到 A。

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

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=[])