2013-02-16 14 views
10

Mam klasy, która ma wiele cech, które są związane, na przykład:W obiekcie klasy, jak atrybuty automatycznej aktualizacji?

class SomeClass: 
    def __init__(self, n=0): 
     self.list = range(n) 
     self.listsquare = [ x**2 for x in self.list ] 

Jeśli zrobię obiekt normalnie, że nie ma problemu, z

a = SomeClass(10) 

będę się 2 listy, a.list i a.listsquare.

Teraz, jeśli chcę złożyć pusty obiekt pierwszy i przypisać jeden atrybut do niej, chcę inne atrybuty mają być automatycznie aktualizowane, na przykład jeśli robię

b = SomeClass() 
b.list = range(5,10) 

Chcę b.listsquare być automatycznie zaktualizowane, a także na odwrót (przypisz b.listsquare i automatyczną aktualizację b.list). czy to możliwe? Czy klasy jest właściwym wyborem?


Dziękuję wszystkim, ale jestem całkowicie przytłoczony wszystkimi odpowiedziami. Czy ktoś może dać kompletne rozwiązanie, abym mógł się nauczyć pisać sam?

chciałbym osiągnąć klasę Foo z 3 atrybutami length, list i listsquare takie, że:

  1. Jeśli robię a = Foo(3), mam a.length = 3, a.list = [0, 1, 2], a.listsquare = [0, 1, 4].
  2. Jeśli wykonam b = Foo().list = [5, 6], otrzymam b.length = 2, b.listsquare = [25, 36].
  3. Jeśli wykonam c = Foo().listsquare = [4, 9], otrzymam c.length = 2, c.list = [2, 3].
+2

Kod dałeś nam nie działa. klasy są definiowane przez "class", a nie "def" i są inicjalizowane za pomocą metody "def __init __ (self, ...)". Użytkownik zdefiniował funkcję z 1 wymaganym parametrem o nazwie "self" i 1 opcjonalnym parametrze "n". Kiedy wywołasz SomeClass (10), funkcja próbuje przypisać "list" do obiektu 10 i nie powiedzie się. - oh, wygląda na to, że pytanie jest ponownie formatowane ... więc nieważne. – tdelaney

+0

Przepraszam, wprowadziłem poprawki. Nie jestem w tej chwili dobrze zaznajomiony. – LWZ

Odpowiedz

13

jeśli aktualizowanie jedną właściwość wyniku aktualizacji na innej nieruchomości jest to, czego szukasz (zamiast ponowne obliczanie wartości nieruchomości downstream o dostępie) używać ustawiające właściwość:

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] 
+0

Czy to oznacza, że ​​muszę zdefiniować 3 właściwości ('size',' list', 'listquare'), więc gdy zaktualizuję jedną z nich, pozostałe 2 zostaną zaktualizowane? – LWZ

+0

to jest poprawne. Zaktualizowałem powyższą odpowiedź, aby działała tak, jak chciałeś - atrybut rozmiaru już jest potrzebny. –

4

Absolutnie. Ale zamiast tego użyj property.

class SomeClass(object): 
    def __init__(self, n=5): 
    self.mylist = range(n) 

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

a = SomeClass() 
a.mylist = [4, 5, 8] 
print a.listsquare 

Buforowanie wartości właściwości jest pozostawione ćwiczeniu dla czytelnika.

+0

Świetnie! A co z tym na odwrót? Czy mogę zdefiniować 'a.listsquare' i uzyskać' a.mylist'? – LWZ

+0

Tak. Po prostu dodaj setera do swojej nieruchomości. –

2

Można też po prostu użyć metody ustawiające, tak:

class SomeClass: 
    def __init__(self, n=5): 
     self.set_list(range(n)) 

    def set_list(self, n): 
     self.list = n 
     self.listsquare = [ x**2 for x in self.list ] 

b = SomeClass() 
b.set_list(range(5,10)) 
1

rozwiązanie @property Ignacio jest super, ale to przelicza listę za każdym razem odwoływać listsquare - że może dostać drogie. Rozwiązanie Mathew jest świetne, ale teraz masz funkcję wywoływania. Możesz łączyć je z funkcją "właściwości". Tutaj definiuję gettera i setera dla my_list (nie mogłem go nazwać "listą"!), Który generuje listsquare:

class SomeClass(object): 

    def __init__(self, n=5): 
     self.my_list = range(n) 

    def get_my_list(self): 
     return self._my_list 

    def set_my_list(self, val): 
     self._my_list = val 
     # generate listsquare when my_list is updated 
     self.my_listsquare = [x**2 for x in self._my_list] 

    # now my_list can be used as a variable 
    my_list = property(get_my_list, set_my_list, None, 'this list is squared') 

x = SomeClass(3) 
print x.my_list, x.my_listsquare 
x.my_list = range(10) 
print x.my_list, x.my_listsquare 

This wyjścia:

[0, 1, 2] [0, 1, 4] 
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 
+0

dzięki temu, że ludzie zwrócili uwagę, źle zainicjowałem listę. – tdelaney

Powiązane problemy