简体   繁体   English

当值不是 None 时,如何用另一个实例覆盖 attrs class 实例

[英]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.

相关问题 Python:当一个 class 用于另一个 class 时,是否可以覆盖/扩展一个实例方法? - Python: Is it possible to override/extend an instance method of one class when it is used in another class? Python 3:如何获取一个类来修改另一个类的实例中的值? - Python 3: How do I get one class to modify values in an instance of another class? 在 python attrs class 中,如何用我自己的方法覆盖生成的 __init__ - in a python attrs class, how can I override generated __init__ with my own 当属性是另一个 attrs 对象时的 Attrs 验证检查 - Attrs validation checking when an attribute is another attrs object 如何将一个类的实例方法monkeypatch到另一个类? - How to monkeypatch one class's instance method to another one? 如果更改类成员值,则打印类实例将导致“无” - Printing a class instance results in None if I change the class member values 在另一个类中使用一个类的实例 - Using an instance of one class in another 声明Class实例时如何返回None - How to return None while declaring Class instance Python模块pytest-mock如何在一个类调用另一个类实例时测试方法调用参数? - Python module pytest-mock how to test method call arguments when one class call another class instance? 如何删除一个列表的 None 值和另一个列表的等效值? - How can I remove None values of one list and the equivalent values from another?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM