2016-09-29 36 views
0

我已經看到了這個答案非常類似的問題:在類對象中,如何在只更改列表中的一個條目時自動更新屬性?

In class object, how to auto update attributes?

我會粘貼在這裏的代碼:

class SomeClass(object): 
    def __init__(self, n): 
     self.list = range(0, n) 

    @property 
    def list(self): 
     return self._list 
    @list.setter 
    def list(self, val): 
     self._list = val 
     self._listsquare = [x**2 for x in self._list ] 

    @property 
    def listsquare(self): 
     return self._listsquare 
    @listsquare.setter 
    def listsquare(self, val): 
     self.list = [int(pow(x, 0.5)) for x in val] 

>>> c = SomeClass(5) 
>>> c.listsquare 
[0, 1, 4, 9, 16] 
>>> c.list 
[0, 1, 2, 3, 4] 
>>> c.list = range(0,6) 
>>> c.list 
[0, 1, 2, 3, 4, 5] 
>>> c.listsquare 
[0, 1, 4, 9, 16, 25] 
>>> c.listsquare = [x**2 for x in range(0,10)] 
>>> c.list 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

在這段代碼中,當我使用更新列表:

>>> c.list = [1, 2, 3, 4] 

c.listsquare將相應更新:

>>> c.listsquare 
[1, 4, 9, 16] 

但是當我嘗試:

>>> c.list[0] = 5 
>>> c.list 
[5, 2, 3, 4] 

Listsquares不更新:

>>> c.listsquare 
[1, 4, 9, 16] 

我怎樣才能讓listsquare自動更新,當我改變列表中只有一個項目?

回答

1

你可以做到這一點的一種方法是通過私人幫手_List類,它幾乎完全像內置的list類,但也有owner屬性。每當一個_List實例的元素中的一個被分配一個值時,它就可以修改其ownerlistsquare屬性以使其保持最新。由於它僅被SomeClass使用,因此它可以嵌套在它內部以提供更多封裝。

class SomeClass(object): 
    class _List(list): 
     def __init__(self, owner, *args, **kwargs): 
      super(SomeClass._List, self).__init__(*args, **kwargs) 
      self.owner = owner 

     def __setitem__(self, index, value): 
      super(SomeClass._List, self).__setitem__(index, value) 
      self.owner.listsquare[index] = int(value**2) 

    def __init__(self, n): 
     self.list = SomeClass._List(self, range(0, n)) 

    @property 
    def list(self): 
     return self._list 
    @list.setter 
    def list(self, val): 
     self._list = val 
     self._listsquare = [x**2 for x in self._list ] 

    @property 
    def listsquare(self): 
     return self._listsquare 
    @listsquare.setter 
    def listsquare(self, val): 
     self.list = [int(pow(x, 0.5)) for x in val] 

c = SomeClass(5) 
print(c.list)  # --> [0, 1, 2, 3, 4] 
print(c.listsquare) # --> [0, 1, 4, 9, 16] 
c.list[0] = 5 
print(c.list)  # --> [5, 1, 2, 3, 4] 
print(c.listsquare) # --> [25, 1, 4, 9, 16] 
1

首先,我會建議你不要通過訪問單個list.setter來改變兩個不同的屬性。之所以這麼做:

>>> c.list[0] = 5 
>>> c.list 
[5, 2, 3, 4] 
>>> c.listsquare 
[1, 4, 9, 16] 

不工作,是你正在訪問c.list .__setitem__方法。

c.list[0] = 5 
is equal to 
c.list.__setitem__(0, 5) 
or 
list.__setitem__(c.list, 0, 5) 
and as such, the list.__setitem__ method isn't the one you've implemented in your class. 

但是,如果你真的想這樣做,你應該重新考慮創建基於self._list的正方形列表。

class SomeClass(object): 
    def __init__(self, n): 
     self.list = range(0, n) 

    @property 
    def list(self): 
     return self._list 

    @list.setter 
    def list(self, val): 
     self._list = val 

    @property 
    def listsquare(self): 
     return [n ** 2 for n in self.list] 

    @listsquare.setter 
    def listsquare(self, val): 
     self.list = [int(pow(x, 0.5)) for x in val] 
相關問題