Mit dem Begriff Bindung bezeichnet man die Auswahl der Implementierung einer Methode zu einem gegebenen Namen. Da Unterklassen Methoden überschreiben können, ist nicht immer ohne weiteres klar, welche Implementierung anzuwenden ist, wie die folgende Diskussion zeigt.
Um die Bindung von Methoden zu verdeutlichen, definieren wir
für jede Unterklasse von Shape
eine Methode __repr__
zur Darstellung der
entsprechenden Figur als Zeichenkette.
Da jede Klasse eine __repr__
-Methode der Klasse object
erbt,
überschreiben wir die geerbte Implementierung mit einer eigenen.
Wir beginnen mit einer __repr__
-Methode für die Shape
-Klasse.
# in class Shape
def __repr__(self):
return "Shape location=" + str(self._location)
Damit die im Attribut _location
gespeicherte Point
-Instanz
in eine sinnvolle Zeichenkette umgewandelt wird, überschreiben wir
die __str__
-Methode in der Point
-Klasse.
# in class Point
def __str__(self):
return "(" + str(self._x) + "," + str(self._y) + ")"
Die drei folgenden Anweisungen erzeugen einen Kreis und ein Rechteck. Anschließend können wir uns in der interaktiven Python-Umgebung deren Darstellung anzeigen lassen.
>>> p = Point(100, 100)
>>> c = Circle(p, 50)
>>> r = Rect(p, 150, 100)
>>> c
Shape location=(100,100)
>>> r
Shape location=(100,100)
Wenn die Rect
-Klasse Zugriff auf die linke obere Ecke mit top_left
sowie auf Breite und Höhe mit
Methoden width
und height
erlaubt, können wir die Methode __repr__
in der Klasse Rect
wie folgt überschreiben.
# in class Rect
def __repr__(self):
return (
"Rect top_left=" + str(self.top_left()) +
" width=" + str(self.width()) +
" height=" + str(self.height())
)
Analog dazu können wir die Methode __repr__
in Circle
definieren,
indem wir die gespeicherten Attributwerte zusammenfassen.
# in class Circle
def __repr__(self):
return (
"Circle center=" + str(self.center()) +
" radius=" + str(self.radius())
)
Wenn wir nun die oben gemachten Eingaben wiederholen, werden diese
beiden unterschiedlichen Implementierungen der __repr__
-Methode
aufgerufen, je nachdem, auf welchem Objekt __repr__
aufgerufen
wird. Dies geschieht selbst dann, wenn wir die Aufrufe in einer
Schleife zusammenfassen.
>>> p = Point(100, 100)
>>> c = Circle(p, 50)
>>> r = Rect(p, 150, 100)
>>> shapes = [c, r]
>>> for i in range(0, len(shapes)):
... print(repr(shapes[i]))
...
Circle center=(100,100) radius=50
Rect top_left=(100,100) width=150 height=100
Obwohl hier textuell nur ein einziger repr
-Aufruf steht, werden in
unterschiedlichen Schleifendurchläufen unterschiedliche
Implementierungen der __repr__
-Methode verwendet, je nachdem zu welcher Klasse das Element shapes[i]
aus der durchlaufenen Liste gehört. Da hier erst zur Laufzeit feststeht, welche Implementierung verwendet wird, spricht man von dynamischer Bindung.
Eine Variante der dynamischen Bindung ist die sogenannte späte Bindung, die wir auch mit Hilfe der __repr__
-Methode illustrieren. Dazu fügen wir der Klasse Shape
eine Methode __str__
hinzu, die das erste von __repr__
gelieferte Wort zurück liefert.
# in class Shape
def __str__(self):
return repr(self).split()[0]
Der Aufruf von repr
verwendet hier die
Implementierung derjenigen Unterklasse von Shape
, auf der
__str__
aufgerufen wurde, selbst wenn diese bei der Definition
von __str__
gar nicht bekannt ist.
Da die Rect
-Klasse die in Shape
definierte Methode __str__
erbt, können wir sie auf dem Rechteck r
aufrufen um seine Beschreibung
zu generieren.
>>> p = Point(100, 100)
>>> r = Rect(p, 150, 100)
>>> print(r)
Rect
Ein Aufruf von print
ruft indirekt __str__
auf.