所以我今天在我的代码中遇到了这个讨厌的bug。我刚刚使用Python属性,并在更新属性时使用它来保留另一个变量中属性的旧值。因此,当调用setter函数时,我需要保存旧值,然后传输新值。
事实证明,在属性上使用+=
时,会调用__iadd__
方法,就地更新属性,然后调用setter。但那时旧的价值已经消失了。这是一些说明问题的代码。
class Container(object):
def __init__(self, val):
self.val = val
def __add__(self, other):
print('in __add__', other)
return Container(self.val + other.val)
def __iadd__(self, other):
print('in __iadd__:', other)
self.val += other.val
return self
def __str__(self):
return str(self.val)
class Test:
def __init__(self):
self._val = Container(0)
@property
def val(self):
return self._val
@val.setter
def val(self, values):
print("changing from {} to {}".format(self._val, values))
self._val = values
test = Test()
print('val=', test.val)
test.val = Container(2)
print('val=', test.val)
test.val = test.val + Container(1)
print('val=', test.val)
test.val += Container(1)
print('val=', test.val)
test.val.__iadd__(Container(1))
print('val=', test.val)
运行时会得到以下结果:
val= 0
changing from 0 to 2
val= 2
in __add__ 1
changing from 2 to 3
val= 3
in __iadd__: 1
changing from 4 to 4
val= 4
in __iadd__: 1
val= 5
它表示它正在改变4到4,但它实际上正在改变3到4而且错过了。所以我想知道这是不是一个错误,我错过了一些东西,或者我不应该使用+ =如果我正在处理一个属性而需要旧值。
答案 0 :(得分:0)
棘手。您可以在getter中缓存旧值。这有点令人讨厌,因为缓存操作是在每次调用getter时执行的,而不是在setter调用上执行的。但无论如何......
class Container(object):
def __init__(self, val):
self.val = val
def __add__(self, other):
print('in __add__', self.val, other)
return Container(self.val + other.val)
def __iadd__(self, other):
print('in __iadd__:', self.val, other)
self.val += other.val
return self
def __str__(self):
return str(self.val)
class Test:
def __init__(self):
self._val = Container(0)
self._prev_val = self._val.val
@property
def val(self):
self._prev_val = self._val.val
return self._val
@val.setter
def val(self, values):
print("changing from {} to {}".format(self._prev_val, values))
self._val = values
test = Test()
print('val=', test.val)
test.val = Container(2)
print('val=', test.val)
test.val = test.val + Container(1)
print('val=', test.val)
test.val += Container(1)
print('val=', test.val)
test.val.__iadd__(Container(1))
print('val=', test.val)
<强>输出强>
val= 0
changing from 0 to 2
val= 2
in __add__ 2 1
changing from 2 to 3
val= 3
in __iadd__: 3 1
changing from 3 to 4
val= 4
in __iadd__: 4 1
val= 5