Variablen¶
Instanz-Variablen¶
Im vorigen Beispiel ist length
eine Instanz-Variable von
Square
-Instanzen, d.h., jede Instanz der Klasse
Square
hat ihre eigene Kopie von length
, und der in dieser Kopie
gespeicherte Wert kann sich von den Werten unterscheiden, die in der
length
-Variable in anderen Instanzen gespeichert sind. In Python könnt ihr
Instanz-Variablen nach Bedarf erstellen, indem ihr sie dem Feld einer
Klasseninstanz zuweist. Wenn die Variable noch nicht existiert, wird sie
automatisch erstellt.
Alle Verwendungen von Instanz-Variablen, sowohl die Zuweisung als auch der
Zugriff, erfordern die explizite Erwähnung der enthaltenen Instanz, d.h. instance.variable
. Ein Verweis auf eine Variable an sich ist
kein Verweis auf eine Instanz-Variable, sondern auf eine lokale Variable in der
ausführenden Methode. Dies ist ein Unterschied zu C++ und Java, wo
Instanz-Variablen auf die gleiche Weise referenziert werden wie lokale
Funktionsvariablen der Methode. Python schreibt hier die explizite Erwähnung der
enthaltenen Instanz vor, und dies ermöglicht eine klare Unterscheidung zwischen
Instanz-Variablen und lokalen Funktionsvariablen.
Klassenvariablen¶
Eine Klassenvariable ist eine Variable, die mit einer Klasse verbunden ist, nicht mit einer Instanz einer Klasse, und auf die alle Instanzen der Klasse zugreifen können. Eine Klassenvariable kann verwendet werden, um einige Informationen auf Klassenebene zu speichern, z.B. wie viele Instanzen der Klasse zu einem bestimmten Zeitpunkt erstellt wurden. Python stellt Klassenvariablen zur Verfügung, obwohl deren Verwendung etwas mehr Aufwand erfordert als in den meisten anderen Sprachen. Außerdem müsst ihr auf eine Wechselwirkung zwischen Klassen- und Instanz-Variablen achten.
Eine Klassenvariable wird durch eine Zuweisung in der Klasse, jedoch außerhalb
der __init__
-Funktion, erzeugt. Nachdem sie erstellt wurde, kann sie von
allen Instanzen der Klasse gesehen werden. ihr könnt eine Klassenvariable
verwenden, um einen Wert für pi
für alle Instanzen der Klasse Circle
zugänglich zu machen:
>>> class Circle:
... pi = 3.14159
... def __init__(self, diameter):
... self.diameter = diameter
... def circumference(self):
... return self.diameter * Circle.pi
...
Wenn ihr diese Definition eingegeben habt, könnt ihr pi
abfragen mit:
>>> Circle.pi
3.14159
Bemerkung
Die Klassenvariable ist mit der Klasse, die sie definiert, verknüpft und in
ihr enthalten. Ihr greift in diesem Beispiel auf Circle.pi
zu, bevor
irgendwelche Circle
-Instanzen erstellt wurden. Es ist offensichtlich,
dass Circle.pi
unabhängig von bestimmten Instanzen der Klasse Circle
existiert.
Ihr könnt auch von einer Methode einer Klasse aus über den Klassennamen auf eine
Klassenvariable zugreifen. Ihr tut dies in der Definition von
Circle.circumference
, wo die Funktion circumference
einen speziellen
Verweis auf Circle.pi
enthält:
>>> c = Circle(3)
>>> c.circumference()
9.424769999999999
Unschön ist jedoch, dass der Klassenname Circle
in der Methode
circumference
verwendet wird, um die Klassenvariable pi
anzusprechen.
Ihr könnt dies vermeiden, indem ihr das spezielle __class__
-Attribut
verwendet, das für alle Python-Klasseninstanzen verfügbar ist. Dieses Attribut
gibt die Klasse zurück, zu der die Instanz gehört, z.B.:
>>> Circle
<class '__main__.Circle'>
>>> c.__class__
<class '__main__.Circle'>
Die Klasse Circle
wird intern durch eine abstrakte Datenstruktur
repräsentiert, und diese Datenstruktur ist genau das, was durch das
__class__
-Attribut von c
, einer Instanz der Klasse Circle
, erhalten
wird. In diesem Beispiel könnt ihr den Wert von Circle.pi
von c
abrufen,
ohne sich explizit auf den Namen der Klasse Circle
zu beziehen:
>>> c.__class__.pi
3.14159
Ihr könnt diesen Code intern in der Methode circumference
verwenden, um den
expliziten Verweis auf die Klasse Circle
loszuwerden; ersetzt Circle.pi
durch self.__class__.pi
.
Es gibt eine kleine Merkwürdigkeit bei Klassenvariablen, die euch verwirren könnte, wenn ihr euch dessen nicht bewusst seid.
Warnung
Wenn Python eine Instanz-Variable sucht und keine Instanz-Variable mit diesem Namen findet, wird der Wert in einer Klassenvariablen mit demselben Namen gesucht und zurückzugeben. Nur wenn keine passende Klassenvariable gefunden werden kann, gibt Python einen Fehler aus. Damit können zwar effizient Standardwerte für Instanz-Variablen implementiert werden; dies führt jedoch auch leicht dazu, versehentlich auf eine Instanz-Variable statt auf eine Klassenvariable zu verweisen, ohne dass ein Fehler gemeldet wird.
Zunächst könnt ihr euch auf die Variable c.pi
beziehen, obwohl c
keine zugehörige Instanz-Variable namens pi
hat. Python versucht
zunächst, eine solche Instanz-Variable zu finden und erst, wenn es keine
Instanz-Variable finden kann, wird eine Klassenvariable pi
in Circle
gesucht:
>>> c1 = Circle(1)
>>> c1.pi
3.14159
Wenn ihr nun feststellt, dass eure Angabe für pi
zu früh gerundet wurde
und ihr sie durch eine präzisere Angabe ersetzen wollt, könntet ihr geneigt
sein, dies folgendermaßen zu ändern:
>>> c1.pi = 3.141592653589793
>>> c1.pi
3.141592653589793
Ihr habt jetzt jedoch lediglich c1
eine neue Instanz-Variable pi
hinzugefügt. Die Klassenvariable Circle.pi
und alle anderen daraus
abgeleiteten Instanzen haben weiterhin nur fünf Nachkommastellen:
>>> Circle.pi
3.14159
>>> c2 = Circle(2)
>>> c1.pi
3.14159