Warnung: das folgende ist eine zu starke Vereinfachung; Ich ignoriere __new__()
und eine Reihe anderer spezieller Klassenmethoden, und viele Details handwaving. Aber diese Erklärung wird dich in Python ziemlich weit bringen.
Wenn Sie eine Instanz einer Klasse in Python zu erstellen, wie der Aufruf ABC() in Ihrem Beispiel:
abc = ABC()
Python erstellt ein neues leeres Objekt und setzt seine Klasse zu ABC. Dann ruft es die __init__()
an, wenn es eine gibt. Schließlich gibt es das Objekt zurück.
Wenn Sie nach einem Attribut eines Objekts fragen, sucht es zuerst in der Instanz. Wenn es es nicht findet, sucht es in der Klasse der Instanz. Dann in der Basisklasse (es) und so weiter. Wenn es niemanden mit dem definierten Attribut findet, löst es eine Ausnahme aus.
Wenn Sie einem Attribut eines Objekts zuweisen, erstellt es dieses Attribut, wenn das Objekt noch keins hat. Dann setzt es das Attribut auf diesen Wert. Wenn das Objekt bereits über ein Attribut mit diesem Namen verfügt, wird der Verweis auf den alten Wert gelöscht und ein Verweis auf den neuen Wert verwendet.
Diese Regeln machen das beobachtete Verhalten einfach vorhersehbar. Nach dieser Zeile:
abc = ABC()
nur die ABC Objekt (die Klasse) hat ein Attribut x benannt. Die abc Instanz hat keine eigene x noch, also, wenn Sie nach einem fragen, werden Sie den Wert ABC.x bekommen. Aber dann weisen Sie das Attribut x sowohl der Klasse als auch dem Objekt zu.Und wenn Sie anschließend diese Attribute untersuchen, beobachten Sie, dass die dort angegebenen Werte immer noch da sind.
Jetzt sollten Sie in der Lage sein, vorherzusagen, was der Code:
class ABC:
x = 6
a = ABC()
ABC.xyz = 5
print(ABC.xyz, a.xyz)
Ja: er druckt zwei Fünfer. Möglicherweise haben Sie erwartet, dass eine AttributeError-Ausnahme ausgelöst wird. Aber Python findet das Attribut in der Klasse - obwohl es hinzugefügt wurde nach die Instanz wurde erstellt.
Dieses Verhalten kann Sie wirklich in Schwierigkeiten bringen. Ein klassischer Anfängerfehler in Python:
class ABC:
x = []
a = ABC()
a.x.append(1)
b = ABC()
print(b.x)
Die [1] gedruckt wird. Alle Instanzen von ABC() teilen dieselbe Liste. Was Sie wahrscheinlich wollten, war das:
class ABC:
def __init__(self):
self.x = []
a = ABC()
a.x.append(1)
b = ABC()
print(b.x)
Das wird eine leere Liste wie erwartet drucken.
Ihre genaue Fragen zu beantworten:
Meine Frage ist, was ist der Zweck eine Variable in der Klassendefinition in Python zu definieren, wenn es scheint, wie ich jemand jederzeit eine beliebige Variable, ohne dabei festlegen ?
Ich nehme an, das bedeutet "warum sollte ich Mitglieder innerhalb der Klasse zuweisen, anstatt innerhalb der __init__
Methode?"
Aus praktischen Gründen bedeutet dies, dass die Instanzen keine eigene Kopie des Attributs haben (oder zumindest noch nicht). Dies bedeutet, dass die Instanzen kleiner sind; Es bedeutet auch, dass der Zugriff auf das Attribut langsamer ist. Es bedeutet auch, dass die Instanzen alle denselben Wert für dieses Attribut haben, was bei veränderbaren Objekten der Fall sein kann oder nicht. Schließlich bedeuten Zuweisungen hier, dass der Wert ein Attribut der Klasse ist, und das ist der einfachste Weg, Attribute für die Klasse festzulegen.
Als rein stilistische Angelegenheit ist es kürzerer Code, da Sie nicht alle diese Instanzen von selbst haben. überall. Darüber hinaus macht es keinen großen Unterschied. Die Zuweisung von Attributen in der __init__
-Methode stellt jedoch sicher, dass sie eindeutig Instanzvariablen sind.
Ich bin nicht sehr konsequent selbst. Das einzige, was ich sicher tun werde, ist die Zuordnung aller veränderbaren Objekte, die ich nicht teilen möchte in der __init__
Methode.
Kennt Python auch den Unterschied zwischen Instanz- und statischen Variablen? Nach dem, was ich sah, würde ich es sagen.
Python-Klassen haben keine statischen Klassenvariablen wie C++. Es gibt nur Attribute: Attribute des Klassenobjekts und Attribute des Instanzobjekts. Und wenn Sie nach einem Attribut fragen, und die Instanz es nicht hat, erhalten Sie das Attribut von der Klasse.
Die nächste Annäherung einer Klasse statischen Variable in Python wäre ein verstecktes Modul Attribut sein, etwa so:
_x = 3
class ABC:
def method(self):
global _x
# ...
Es ist nicht Teil der Klasse per se.Aber das ist eine übliche Python-Redewendung.
Ich glaube, ein Teil der Grund für Ihre Verwirrung ist, dass alle Variablen in der Klasse ABC (und der Instanz abc) "öffentlich" sind. Sie werden auch dynamisch erstellt. so "abc.x = 2" erstellt tatsächlich eine neue nicht statische Elementvariable in der Instanz abc ... Das heißt ... "abc.x = 2" würde funktionieren, wenn es keine statische Variable x gäbe. Das könnte klarer sein, wenn Sie abc.y = 2 ausprobieren. – Tom
@Tom: Bitte posten Sie Ihre Antwort als Antwort, nicht als Kommentar. Es ist sehr verwirrend, Antworten als Kommentare zu sehen. –