2017-02-01 52 views
2

所以我今天在我的代碼中遇到了這個討厭的bug。我最近剛剛使用Python屬性,並且在屬性更新時使用它來保存另一個變量中舊屬性的值。因此,當調用setter函數時,我需要保存舊值,然後再傳輸新值。這是一個錯誤? Python屬性無法正常工作+ =

事實證明,當在一個屬性上使用+=時,__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

你可能想看看http://stackoverflow.com/questions/11987949/how-to-implement-iadd-for-a -python-property – Jan

+0

這幾乎有幫助。如果我在對象上用__add__替換了__iadd__,那麼它會修復它。但只是我的運氣'__Iadd__'是numpy數組的一個ready-only屬性。所以我剛剛擺脫了setter,並使其成爲一個非屬性集函數。 – TheLoneMilkMan

回答

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 
相關問題