[英]How to override an attrs class instance with another one when the values are not None
My goal is to be able to merge multiple instances of the same attrs
class and skip 'None' values.我的目标是能够合并相同attrs
class 的多个实例并跳过“无”值。
This allows me to create default values and later override them when I need to.这允许我创建默认值,然后在需要时覆盖它们。
An example of the expected code-预期代码的示例-
from attr import attrs
@attrs(auto_attribs=True)
class A:
a: int = None
b: int = None
instance_1 = A(a=1, b=2)
instance_2 = A(b=3)
# Expected result
instance_3 = merge_instances(instance_1, instance_2)
# instance_3 = A(a=1, b=3)
The best solution I currently found was the following-我目前找到的最佳解决方案如下 -
from attr import attrs
@attrs(auto_attribs=True)
class A:
a: int = None
b: int = None
def merge_instances(instance_1, instance_2):
dict_1 = instance_1.__dict__
dict_2 = instance_2.__dict__
new_values = {}
for key in dict_1:
new_values[key] = dict_2[key] if dict_2[key] is not None else dict_1[key]
return A(**new_values)
if __name__ == '__main__':
instance_1 = A(a=1, b=2)
instance_2 = A(b=3)
instance_3 = merge_instances(instance_1, instance_2)
print(instance_3)
Which kind of feels like a hack.哪种感觉像黑客。 If anyone has a simpler solution I'd love to hear it!如果有人有更简单的解决方案,我很想听听!
This is cleaner这个更干净
def merge_instances(instance_1, instance_2):
dict_1 = instance_1.__dict__
dict_2 = instance_2.__dict__
new_values = {k: dict_2[k] or dict_1[k] for k in dict_1}
return A(**new_values)
Since this function is strictly related to class A
, you can make it a classmethod由于此 function 与 class A
严格相关,因此您可以将其设为类方法
from attr import attrs
@attrs(auto_attribs=True)
class A:
a: int = None
b: int = None
@classmethod
def merge_instances(cls, instance_1, instance_2):
dict_1 = instance_1.__dict__
dict_2 = instance_2.__dict__
return cls(
**{k: dict_2[k] or dict_1[k] for k in dict_1}
)
if __name__ == '__main__':
instance_1 = A(a=1, b=2)
instance_2 = A(b=3)
instance_3 = A.merge_instances(instance_1, instance_2)
Since you're already using attrs, this is more idiomatic:由于您已经在使用 attrs,因此这更惯用:
from attrs import define, fields
@define
class A:
a: int = None
b: int = None
instance_1 = A(a=1, b=2)
instance_2 = A(b=3)
def merge_instances(i1: A, i2: A) -> A:
kw = {}
for f in fields(A):
v = getattr(i2, f.name)
kw[f.name] = v if v is not None else getattr(i1, f.name)
return A(**kw)
assert A(a=1, b=3) == merge_instances(instance_1, instance_2)
Another possibility that is one line longer, but feels cleaner to me is to use attrs.evolve()
:另一种可能更长,但对我来说感觉更干净的可能性是使用attrs.evolve()
:
def merge_instances(i1: A, i2: A) -> A:
kw = {}
for f in fields(A):
v = getattr(i2, f.name)
if v is not None:
kw[f.name] = v
return evolve(i1, **kw)
Even nicer if you get to use the walrus:如果你能使用海象就更好了:
def merge_instances(i1: A, i2: A) -> A:
kw = {}
for f in fields(A):
if (v := getattr(i2, f.name)) is not None:
kw[f.name] = v
return evolve(i1, **kw)
which could be simplified even further:这可以进一步简化:
def merge_instances(i1: A, i2: A) -> A:
return evolve(
i1,
**{
f.name: v
for f in fields(A)
if (v := getattr(i2, f.name)) is not None
},
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.