2013-02-16 18 views
10

ho una classe che ha più attributi che sono legati, per esempio:In oggetto classe, come aggiornare automaticamente gli attributi?

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

Se faccio un oggetto normalmente che avrebbe nessun problema, con

a = SomeClass(10) 

mi metterò 2 liste, a.list e a.listsquare.

Ora, se io voglio fare un oggetto vuoto prima, e assegnare un attributo ad esso, voglio gli altri attributi per essere aggiornati automaticamente, ad esempio se lo faccio

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

voglio b.listsquare per essere automaticamente aggiornato, e anche il contrario (assegnare b.listsquare e aggiornamento automatico b.list). È possibile? Classe la scelta giusta per questo?


Grazie a tutti voi, ma sono completamente sopraffatto da tutte le diverse risposte. Qualcuno può dare una soluzione completa in modo che io possa imparare a scrivere la mia?

vorrei realizzare una classe Foo con 3 attributi length, list e listsquare tale che:

  1. Se lo faccio a = Foo(3), ottengo a.length = 3, a.list = [0, 1, 2], a.listsquare = [0, 1, 4].
  2. Se faccio b = Foo().list = [5, 6], ottengo b.length = 2, b.listsquare = [25, 36].
  3. Se faccio c = Foo().listsquare = [4, 9], ottengo c.length = 2, c.list = [2, 3].
+2

Il codice che hai dato a noi non funziona. le classi sono definite da 'class' non 'def' e sono inizializzate tramite il metodo 'def __init __ (self, ...)'. Hai definito una funzione con 1 parametro richiesto chiamato 'self' e 1 parametro opzionale chiamato 'n'. Quando chiamate SomeClass (10), la funzione prova ad assegnare 'lista' all'oggetto 10 e fallisce. - oh, sembra che la domanda sia stata riformattata ... quindi non importa. – tdelaney

+0

Siamo spiacenti, ho apportato le correzioni. Non ho molta familiarità con questo adesso. – LWZ

risposta

13

se si desidera aggiornare una proprietà a causa di un aggiornamento su un'altra proprietà è quello che state cercando (invece di ricalcolare il valore della proprietà a valle in materia di accesso) utilizzare setter di proprietà:

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

Ciò significa che devo definire 3 proprietà ('size',' list', 'listsquare'), quindi quando aggiorno uno di loro gli altri 2 si aggiorneranno? – LWZ

+0

corretto. ho aggiornato la risposta di cui sopra per funzionare nel modo desiderato: l'attributo di dimensione è più necessario. –

4

Assolutamente. Ma usa invece un 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 

La memorizzazione nella cache del valore della proprietà viene lasciata come esercizio per il lettore.

+0

Ottimo! E il contrario? Posso definire 'a.listsquare' e ottenere' a.mylist'? – LWZ

+0

Sì. Basta aggiungere un setter alla tua proprietà. –

2

È anche possibile usare i metodi setter, in questo modo:

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

soluzione @property di Ignacio è grande ma si ricalcola la lista ogni volta che si fa riferimento a listsquare - che potrebbe ottenere costoso. La soluzione di Mathew è ottima, ma ora hai chiamate di funzione. È possibile combinare questi con la funzione 'proprietà'. Qui definisco un getter e un setter per my_list (non riuscivo a chiamarlo 'list'!) Che genera 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 

Questo uscite:

[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

grazie alla gente che ha sottolineato che avevo inizializzato la lista in modo errato. – tdelaney

Problemi correlati