2015-09-11 15 views
5

Ich habe mir die Stack Overflow-Frage Counting instances of a class? angesehen, und ich bin nicht sicher, warum diese Lösung funktioniert und eine, die eine einfache Addition verwendet, nicht. Ich denke, das ist eher eine Frage, wie Klassen- und Instanzvariablen gespeichert und auf sie zugegriffen wird.Ändern eines Klassenattributs innerhalb von __init__

Hier ist der Code, den ich denke, sollte funktionieren, sondern erzeugt stattdessen 4 für jeden 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 

Die self.num +=1 Aussage etwas arbeitet (die Zugabe geschieht, aber nicht die Zuordnung).

Was passiert unter der Haube, die diese Aufgabe hier fehlschlägt, während die itertools.count Zuweisung in der anderen Frage Lösung gelingt?

Antwort

4

self.num += 1 bedeutet, im Grunde 'nehmen Sie den Wert von self.num, erhöhen Sie es und weisen Sie auf self.num.

Das Nachschlagen eines Attributs auf self findet die Klassenvariable, wenn keine entsprechende Instanzvariable vorhanden ist. Zuweisen wird jedoch immer auf eine Instanzvariable schreiben. Also, das versucht eine Instanz zu finden var, fails, fällt zurück auf eine Klasse var, holt den Wert, inkrementiert ihn und weist dann einer Instanz zu var.

Der Grund, warum die Antwort auf die verknüpfte Frage funktioniert, ist, dass keine Zuweisung stattfindet; Sie rufen next() direkt auf der Klassenvariablen auf, ihr Wert ist mutiert, aber der Name wird nicht neu zugewiesen.

5

Integer implementieren __iadd__ (In-Place-Add für +=) nicht, da sie unveränderlich sind. Der Dolmetscher fällt zurück auf Standardbelegung und __add__ statt, so dass die Zeile:

self.num += 1 

wird:

self.num = self.num + 1 

Auf der rechten Seite Sie foo.num (dh 3) über self.num erhalten, wie Sie erwartet , aber das Interessante ist hier, dass dem Instanzattribut numSchatten das Klassenattribut zuweist. So ist die Linie tatsächlich entspricht:

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

Alle Instanzen mit self.num == 4 am Ende und die Klasse bleibt foo.num == 3. Stattdessen habe ich den Verdacht, was man wollte, ist:

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

Alternativ können Sie es als @classmethod implementieren könnte, mehr explizit auf die Klasse arbeiten:

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

Alternativ 'Selbst .__ Klasse __ num + = 1 ' – robert

+1

@ Robert, die funktionieren würde, aber ich es finden ein bisschen peinlich – jonrsharpe

2

Augmented Zuordnung aktualisiert nicht die Klasse Variable.Es tut dies:

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

Beachten Sie die Zuordnung wieder zu self.num da! Daher bleibt Ihr Klassenattribut unberührt. Die object.__iadd__() method für Ganzzahlen kann die Zahl nicht an Ort und Stelle ändern, da Ganzzahlen unveränderlich sind, so ändert sich foo.num nie.

Sie müssen explizit die Klassenvariable verweisen.

foo.num += 1 

oder

self.__class__.num += 1 
Verwandte Themen