2016-09-29 2 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 присваивается значение, он может затем изменить свойство listsquare своего owner, чтобы поддерживать его в актуальном состоянии. Так как он используется только 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] 
Смежные вопросы