Was ich will, ist dieses Verhalten:
class a:
list = []
x = a()
y = a()
x.list.append(1)
y.list.append(2)
x.list.append(3)
y.list.append(4)
print(x.list) # prints [1, 3]
print(y.list) # prints [2, 4]
Was beim Drucken wirklich passiert, ist natürlich:
print(x.list) # prints [1, 2, 3, 4]
print(y.list) # prints [1, 2, 3, 4]
Offensichtlich teilen sie die Daten in der Klasse a
. Wie erhalte ich separate Instanzen, um das gewünschte Verhalten zu erzielen?
list
als Attributname verwenden.list
ist eine integrierte Funktion zum Erstellen einer neuen Liste. Sie sollten Namensklassen mit Großbuchstaben schreiben.Antworten:
Du willst das:
Durch das Deklarieren der Variablen in der Klassendeklaration werden sie zu "Klassen" -Mitgliedern und nicht zu Instanzmitgliedern. Wenn Sie sie innerhalb der
__init__
Methode deklarieren, wird sichergestellt, dass neben jeder neuen Instanz des Objekts eine neue Instanz der Mitglieder erstellt wird. Dies ist das Verhalten, nach dem Sie suchen.quelle
x.list = []
, können Sie es ändern und keine anderen beeinflussen. Das Problem , das Sie Gesicht ist , dassx.list
undy.list
die gleiche Liste sind, also wenn Sie Append rufen auf einem, den anderen beeinflusst.__init__
.Die akzeptierte Antwort funktioniert, aber ein bisschen mehr Erklärung tut nicht weh.
Klassenattribute werden beim Erstellen einer Instanz nicht zu Instanzattributen. Sie werden zu Instanzattributen, wenn ihnen ein Wert zugewiesen wird.
Im ursprünglichen Code wird dem
list
Attribut nach der Instanziierung kein Wert zugewiesen . es bleibt also ein Klassenattribut. Das Definieren einer Liste innerhalb__init__
funktioniert, da__init__
es nach der Instanziierung aufgerufen wird. Alternativ würde dieser Code auch die gewünschte Ausgabe erzeugen:Das verwirrende Szenario in der Frage wird jedoch niemals unveränderlichen Objekten wie Zahlen und Zeichenfolgen passieren, da deren Wert nicht ohne Zuweisung geändert werden kann. Beispielsweise funktioniert ein Code ähnlich dem Original mit dem Attributtyp Zeichenfolge problemlos:
Zusammenfassend: Klassenattribute werden genau dann zu Instanzattributen, wenn ihnen nach der Instanziierung ein Wert zugewiesen wird, ob sie sich in der
__init__
Methode befinden oder nicht . Dies ist eine gute Sache, da Sie auf diese Weise statische Attribute haben können, wenn Sie einem Attribut nach der Instanziierung niemals einen Wert zuweisen.quelle
Sie haben "list" als "Eigenschaft auf Klassenebene" und nicht als "Eigenschaft auf Instanzebene" deklariert. Damit Eigenschaften auf Instanzebene festgelegt werden, müssen Sie sie durch Referenzieren mit dem Parameter "self" in der
__init__
Methode (oder je nach Situation an anderer Stelle) initialisieren .Sie müssen die Instanzeigenschaften in der
__init__
Methode nicht unbedingt initialisieren , dies erleichtert jedoch das Verständnis.quelle
Obwohl die akzeptierte Antwort genau richtig ist, möchte ich eine kleine Beschreibung hinzufügen.
Machen wir eine kleine Übung
Definieren Sie zunächst eine Klasse wie folgt:
Was haben wir hier?
temp
das eine Zeichenfolge ist__init__
Methode, die setztself.x
self.temp
Bis jetzt ziemlich einfach, ja? Jetzt fangen wir an, mit dieser Klasse herumzuspielen. Initialisieren wir zuerst diese Klasse:
Gehen Sie nun wie folgt vor:
Nun,
a.temp
hat wie erwartet funktioniert, aber wie zum Teufel hat esA.temp
funktioniert? Nun, es hat funktioniert, weil Temp ein Klassenattribut ist. Alles in Python ist ein Objekt. Hier ist A auch ein Objekt der Klassetype
. Daher ist das Attribut temp ein Attribut, das von derA
Klasse gehalten wird. Wenn Sie den Wert von temp durchA
(und nicht durch eine Instanz vona
) ändern, wird der geänderte Wert in der gesamten Instanz derA
Klasse wiedergegeben. Lassen Sie uns fortfahren und das tun:Interessant, nicht wahr? Und beachten Sie, dass
id(a.temp)
undid(A.temp)
sind immer noch die gleichen .Jedes Python-Objekt erhält automatisch ein
__dict__
Attribut, das die Liste der Attribute enthält. Lassen Sie uns untersuchen, was dieses Wörterbuch für unsere Beispielobjekte enthält:Beachten Sie, dass das
temp
Attribut unterA
den Attributen der Klasse aufgeführt ist, währendx
es für die Instanz aufgeführt ist.Wie kommt es, dass wir einen definierten Wert erhalten ,
a.temp
wenn es nicht einmal für die Instanz aufgeführt wirda
. Nun, das ist die Magie von__getattribute__()
Methode. In Python ruft die gepunktete Syntax diese Methode automatisch auf, sodassa.temp
Python beim Schreiben ausgeführt wirda.__getattribute__('temp')
. Diese Methode führt die Attributsuchaktion aus, dh sie ermittelt den Wert des Attributs, indem sie an verschiedenen Stellen sucht.Die Standardimplementierung der
__getattribute__()
Suche durchsucht zunächst das interne Wörterbuch ( dikt ) eines Objekts und dann der Typ des Objekts selbst . In diesem Falla.__getattribute__('temp')
wird zuersta.__dict__['temp']
und dann ausgeführta.__class__.__dict__['temp']
Okay, jetzt lass uns unsere benutzen
change
Methode:Nun, da wir verwendet haben
self
,print(a.temp)
gibt uns einen anderen Wert alsprint(A.temp)
.Wenn wir nun
id(a.temp)
und vergleichenid(A.temp)
, werden sie unterschiedlich sein.quelle
Ja, Sie müssen im "Konstruktor" deklarieren, wenn Sie möchten, dass die Liste eine Objekteigenschaft und keine Klasseneigenschaft wird.
quelle
Fast jede Antwort hier scheint einen bestimmten Punkt zu verfehlen. Klassenvariablen werden niemals zu Instanzvariablen, wie der folgende Code zeigt. Durch die Verwendung einer Metaklasse zum Abfangen der Variablenzuweisung auf Klassenebene können wir sehen, dass bei einer Neuzuweisung von a.myattr die magische Methode der Feldzuweisung für die Klasse nicht aufgerufen wird. Dies liegt daran, dass durch die Zuweisung eine neue Instanzvariable erstellt wird . Dieses Verhalten hat absolut nichts mit der Klassenvariablen zu tun, wie die zweite Klasse zeigt, die keine Klassenvariablen hat und dennoch eine Feldzuweisung zulässt.
ZUSAMENFASSEND Klassenvariablen haben NICHTS mit Instanzvariablen zu tun.
Genauer gesagt, sie befinden sich zufällig im Bereich der Suche nach Instanzen. Klassenvariablen sind tatsächlich Instanzvariablen im Klassenobjekt selbst. Sie können auch Metaklassenvariablen haben, wenn Sie möchten, da Metaklassen selbst ebenfalls Objekte sind. Alles ist ein Objekt, unabhängig davon, ob es zum Erstellen anderer Objekte verwendet wird oder nicht. Lassen Sie sich also nicht auf die Semantik der Verwendung der Wortklasse in anderen Sprachen ein. In Python ist eine Klasse eigentlich nur ein Objekt, mit dem bestimmt wird, wie andere Objekte erstellt werden und wie sie sich verhalten. Metaklassen sind Klassen, die Klassen erstellen, um diesen Punkt weiter zu veranschaulichen.
quelle
Um Ihre von einer anderen Instanz gemeinsam genutzte Variable zu schützen, müssen Sie jedes Mal, wenn Sie eine Instanz erstellen, eine neue Instanzvariable erstellen. Wenn Sie eine Variable innerhalb einer Klasse deklarieren, ist dies eine Klassenvariable, die von allen Instanzen gemeinsam genutzt wird. Wenn Sie es zum Beispiel klug machen möchten, müssen Sie den Init verwenden Methode verwenden, um die Variable gemäß der Instanz neu zu initialisieren
Aus Python-Objekten und -Klassen von Programiz.com :
Beispielsweise:
quelle