如何在更新属性时验证对象仍然符合这些条件?

huangapple go评论77阅读模式
英文:

How can I verify that the object is still correct with these conditions when I update the attribute?

问题

如何在每次属性更新后运行检查?

class Test:
    def __init__(self, A, B, C):
        self.A = A
        self.B = B
        self.C = C
        self.check()

    def check(self):
        if self.A + self.B + self.C > 10:
            raise ValueError

    def __str__(self):
        return f'{self.A}, {self.B}, {self.C}'

t = Test(2, 2, 2)
t.A = 8
print(t)
# 输出: 8, 2, 2

我尝试使用__setattr__,但这样会在对象尚未分配所有属性时执行检查。

英文:

How do I make the check run after every attribute update?

class Test:
    def __init__(self, A, B, C):
        self.A = A
        self.B = B
        self.C = C
        self.check()

    def check(self):
        if self.A + self.B + self.C > 10:
            raise ValueError

    def __str__(self):
        return f'{self.A}, {self.B}, {self.C}'


>> t = Test(2, 2, 2)
>> t.A = 8
>> print(t)
>> 8, 2, 2

I tried to do it with setattr but then the check will execute when not all attributes are assigned to the object yet

答案1

得分: 1

Here is the translated content you requested:

作为一种替代方案,可以在初始化之后禁用__setattr__的链接解决方案,您可以将属性包装为属性,并编写显式的设置器,在分配给实际属性之前检查条件。

class Test:
    def __init__(self, A, B, C):
        self._A = A
        self._B = B
        self._C = C

    def _check(self, **newValues):
        d = {"A": self._A, "B": self._B, "C": self._C}
        d.update(newValues)
        if sum(d.values()) > 10:
            raise ValueError

    @property
    def A(self):
        return self._A
    @A.setter
    def A(self, value):
        self._check(A=value)
        self._A = value

    @property
    def B(self):
        return self._B
    @B.setter
    def B(self, value):
        self._check(B=value)
        self._B = value

    @property
    def C(self):
        return self._C
    @C.setter
    def C(self, value):
        self._check(C=value)
        self._C = value

    def __str__(self):
        return f'{self.A}, {self.B}, {self.C}'

t = Test(2, 2, 2)
t.B = 8 # ValueError

此外,根据您在问题中编写的check的方式,您需要在进行检查之前更改对象。这意味着如果出现错误,对象仍然会被修改为可能是不正确的值。通过我在此答案中实现的方式,您可以在不更改实际值的情况下进行检查,因此如果出现错误,对象将保持不变。

英文:

As an alternative to linked solution with disabling __setattr__ until after initialisation, you can wrap the attributes as property, writing them explicit setters that check the condition before assigning to actual attribute.

class Test:
    def __init__(self, A, B, C):
        self._A = A
        self._B = B
        self._C = C

    def _check(self, **newValues):
        d = {"A": self._A, "B": self._B, "C": self._C}
        d.update(newValues)
        if sum(d.values()) > 10:
            raise ValueError

    @property
    def A(self):
        return self._A
    @A.setter
    def A(self, value):
        self._check(A=value)
        self._A = value


    @property
    def B(self):
        return self._B
    @B.setter
    def B(self, value):
        self._check(B=value)
        self._B = value
    
    @property
    def C(self):
        return self._C
    @C.setter
    def C(self, value):
        self._check(C=value)
        self._C = value


    def __str__(self):
        return f'{self.A}, {self.B}, {self.C}'
    
t = Test(2,2,2)
t.B = 8 # ValueError

Also, with check written the way you did in your question, you need to change the object before making the check. Which means if error is thrown, the object will still be modified to presumably incorrect value. With the way I implemented it in this answer, you can make check without changing the actual value, so in case of error the object remains unchanged.

huangapple
  • 本文由 发表于 2023年4月13日 21:25:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76005989.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定