2015-09-11 11 views
5

Stavo osservando la domanda Stack Overflow Counting instances of a class? e non sono sicuro del motivo per cui la soluzione funzioni e l'altra con l'aggiunta semplice no. Immagino che questa sia più una questione di come le variabili di classe e di istanza siano archiviate e accessibili.Modifica di un attributo di classe all'interno di __init__

Ecco il codice penso dovrebbe funzionare, ma invece produce 4 per ogni id:

class foo(): 
     num = 3 # trying 3 instead of 0 or 1 to make sure the add is working 

     def __init__(self): 
     self.num += 1 
     self.id = self.num 

f = foo() 
g = foo() 

print f.id # 4 
print g.id # 4 

La dichiarazione self.num +=1 è in qualche modo funziona (l'aggiunta sta accadendo, ma non l'assegnazione).

Cosa sta succedendo sotto il cofano che sta facendo fallire questo compito qui, mentre l'assegnazione itertools.count riesce nella soluzione dell'altro problema?

risposta

4

self.num += 1 significa, in pratica, "prendere il valore di self.num, incrementarlo e assegnarlo a self.num.

Cercare un attributo su self troverà la variabile di classe se non c'è alcuna variabile di istanza corrispondente. Tuttavia, l'che assegna scrive sempre su una variabile di istanza. Quindi, questo cerca di trovare un'istanza var, fallisce, ricade in una classe var, ottiene il valore, lo incrementa, quindi assegna a un'istanza var.

Il motivo per cui la risposta alla domanda collegata funziona è perché non è in corso alcuna assegnazione; chiamano next() direttamente sulla variabile di classe, il suo valore viene mutato ma il nome non viene riassegnato.

5

I numeri interi non implementano __iadd__ (in-place add, per +=), poiché sono immutabili. L'interprete ricade assegnazione standard e __add__ invece, così la linea:

self.num += 1 

diventa:

self.num = self.num + 1 

Sul lato destro si ottiene foo.num (cioè 3) tramite self.num, come previsto , ma la cosa interessante qui è che assegnando all'attributo di istanza numombre l'attributo di classe. Così la linea è in realtà equivale a:

self.num = foo.num + 1 # instance attribute equals class attribute plus one 

Tutti casi finire con self.num == 4 e la classerimane foo.num == 3. Invece, ho il sospetto che quello che volevi è:

foo.num += 1 # explicitly update the class attribute 

In alternativa, è possibile implementare come un @classmethod, lavorando sulla classe più esplicitamente:

class Foo(): # note naming convention 

    num = 3 

    def __init__(self): 
     self.increment() 
     self.id = self.num # now you're still accessing the class attribute 

    @classmethod 
    def increment(cls): 
     cls.num += 1 
+0

In alternativa, 'self .__ class __ num + = 1' – robert

+1

@ Robert che avrebbe funzionato, ma io lo trovo un po 'imbarazzante – jonrsharpe

2

assegnazione Augmented non aggiorna la classe variabile.Lo fa:

tmp = self.num 
self.num = tmp.__iadd__(1) 

nota l'assegnazione di nuovo a self.num lì! In quanto tale, il tuo attributo di classe rimane intatto. Lo object.__iadd__() method per i numeri interi non può modificare il numero sul posto perché gli interi sono immutabili, quindi foo.num non cambia mai.

È necessario fare riferimento in modo esplicito la variabile di classe:.

foo.num += 1 

o

self.__class__.num += 1 
Problemi correlati