2012-01-02 5 views
26

ho problemi a capire come funzionano le variabili di classe/istanza in python. Non capisco perché quando provo questo codice la variabile di lista sembra essere una variabile di classevariabili di istanza della classe python e variabili di classe

class testClass(): 
    list = [] 
    def __init__(self): 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

uscita:

['thing'] 
['thing', 'thing'] 

e quando faccio questo sembra essere un caso variabile

class testClass(): 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

uscita:

['thing'] 
['thing'] 

molte grazie

jon

+1

Se ho capito bene, stai chiedendo delle motivazioni alla base di una particolare decisione progettuale riguardante la sintassi di Python. Per tali domande, la risposta migliore è "perché si adatta allo spirito della lingua", o più spudoratamente: "chiedi al suo creatore". – Xion

+0

ok quindi le variabili sono variabili di classe per impostazione predefinita, da cui derivava la mia confusione, che avrebbe dovuto essere la mia domanda, fare variabili predefinite alle variabili di classe –

+4

@jonathantopf No, le variabili NON sono variabili di classe per impostazione predefinita. In Python non si dichiarano varables. Del resto, non sono in realtà variabili (python è una _variableless_ lanuage), solo nomi. E non dichiari o assegni nomi, li leghi a un oggetto. E ogni oggetto nel runtime ha un dizionario di nomi per oggetto. E anche se due oggetti sono della stessa classe, possono avere dizionari molto diversi. – rodrigo

risposta

40

Questo è a causa del modo Python risolve i nomi con il .. Quando si scrive self.list, il runtime di Python tenta di risolvere il nome list prima cercandolo nell'oggetto istanza e, se non trovato nell'istanza della classe.

Vediamo in esso, passo dopo passo

self.list.append(1) 
  1. C'è un nome list nell'oggetto self?
    • Sì: usalo! Finire.
    • No: Vai 2.
  2. C'è un nome list nell'istanza classe dell'oggetto self?
    • Sì: usalo! Fine
    • No: Errore!

Ma quando si associa un nome le cose sono diverse:

self.list = [] 
  1. C'è un nome list nell'oggetto self?
    • Sì: sovrascriverlo!
    • No: legalo!

Quindi, che è sempre una variabile di istanza.

Il primo esempio crea un list nell'istanza di classe, poiché questo è l'ambito attivo in quel momento (no self ovunque). Ma il tuo secondo esempio crea uno list esplicitamente nell'ambito di self.

Più interessante potrebbe essere l'esempio:

class testClass(): 
    list = ['foo'] 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

x = testClass() 
print x.list 
print testClass.list 
del x.list 
print x.list 

che stamperà:

['thing'] 
['foo'] 
['foo'] 

Nel momento in cui si elimina l'istanza nome il nome della classe è visibile attraverso il riferimento self.

+0

ok sto seguendo, in questo caso c'è un modo per definire le variabili di istanza al di fuori della funzione __init__, ho appena provato a fare 'self.list []' al di fuori di __init__, questo ha senso ma c'è un modo? –

+0

@jonathantopf: le variabili di istanza possono essere create solo quando si dispone di un'istanza. Devono essere creati in un metodo chiamato su istanza. L'altra opzione è di sovraccaricare '__new__' e crearli lì, ma questo è davvero brutto in quanto non è ciò che' __new__' è veramente per, e non è davvero meglio che crearli in '__init__'. Che cosa, per favore, pensi che ti serve questa capacità? Potresti creare una meta-classe che sovraccarichi '__new__' per guardare attraverso il dettato della classe e copiare le cose nel dettato dell'istanza. Ma questo è veramente brutto. – Omnifarious

+0

:) punto preso, ha senso, odio fare domande del genere ma a volte è il modo migliore per scoprire se quello che sto pensando è pazzo o no, ora lo so! –

0

Quando si crea un'istanza di una classe, il metodo __init__ viene eseguito automaticamente.

Nel primo caso l'elenco è un attributo di classe ed è condiviso da tutte le sue istanze. Hai due cose perché ne hai aggiunto una quando esegui l'istanziazione di p e un'altra quando instanziata f (la prima era già stata aggiunta alla prima chiamata).

3

Nel primo esempio, list è un attributo della classe, condiviso da tutte le istanze di esso. Ciò significa che si può anche accedere senza avere un oggetto di tipo testClass:

>>> class testClass(): 
...  list = [] 
...  def __init__(self): 
...    self.list.append("thing") 
... 
>>> testClass.list 
[] 
>>> testClass.list.append(1) 
>>> testClass.list 
[1] 

Ma tutti gli oggetti condividono l'attributo list con la classe e l'altro:

>>> testObject = testClass() 
>>> testObject.list 
[1, 'thing'] 
>>> testClass.list 
[1, 'thing'] 
>>> 
>>> testObject2 = testClass() 
>>> testClass.list 
[1, 'thing', 'thing'] 
>>> testObject2.list 
[1, 'thing', 'thing'] 
4

Python ha regole interessanti di ricerca nomi. Se davvero si vuole piegare la tua mente, provare questo codice:

class testClass(): 
    l = [] 
    def __init__(self): 
     self.l = ['fred'] 

Questo darà ogni istanza una variabile chiamata l che maschera la classe variabile l. Sarai comunque in grado di ottenere la variabile di classe se lo fai self.__class__.l.

Il modo in cui penso è questo ... Ogni volta che si fa instance.variable (anche per i nomi dei metodi, sono solo variabili a cui i valori sono funzioni) lo cerca nel dizionario dell'istanza. E se non riesce a trovarlo lì, cerca di cercarlo nel dizionario della classe dell'istanza. Questo è solo se la variabile viene "letta". Se viene assegnato, crea sempre una nuova voce nel dizionario di istanza.

+0

Quali complicazioni subdole! Questa risposta mi è stata di grande aiuto, perché il caso di "leggere e scrivere" mi dava fastidio. – dotslash