簡體   English   中英

當值不是 None 時,如何用另一個實例覆蓋 attrs class 實例

[英]How to override an attrs class instance with another one when the values are not None

我的目標是能夠合並相同attrs class 的多個實例並跳過“無”值。

這允許我創建默認值,然后在需要時覆蓋它們。

預期代碼的示例-

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)

我目前找到的最佳解決方案如下 -

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)

哪種感覺像黑客。 如果有人有更簡單的解決方案,我很想聽聽!

這個更干凈

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)

由於此 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)

由於您已經在使用 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)

另一種可能更長,但對我來說感覺更干凈的可能性是使用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)

如果你能使用海象就更好了:

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)

這可以進一步簡化:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM