Duck-Typing
aus Wikipedia, der freien Enzyklopädie
Duck-Typing ist ein Konzept der Objektorientierung, das die Anwendbarkeit bestimmter Verfahren nicht an die Ableitung der Klasse von einer bestimmten Superklasse oder der förmlichen Implementierung einer Spezifikation knüpft, sondern an das Vorhandensein bestimmter Merkmale, in Anlehnung an James Whitcomb Rileys Gedicht
„When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.“
was übersetzt bedeutet: „Wenn ich einen Vogel sehe, der wie eine Ente läuft, wie eine Ente schwimmt und wie eine Ente schnattert, dann nenne ich diesen Vogel eine Ente.“ Duck-Typing ist charakteristisch für objektorientierte Skriptsprachen wie Python und Ruby.
Beim Duck-Typing wird zur Laufzeit des Programms geprüft, ob ein Objekt die entsprechenden Merkmale unterstützt. Dies führt wie bei allen dynamischen Typsystemen zu einer erhöhten Flexibilität, reduziert aber ebenso die Möglichkeit, statisch zur Übersetzungszeit Fehler im Programm zu finden. In Sprachen wie Java und C# ist es erforderlich, bei der Definition einer Klasse anzugeben, welche Interfaces implementiert werden sollen. Diese Sprachen erlauben es somit nicht, nach der Fertigstellung einer Klasse festzulegen, dass die Klasse zusätzlich noch ein anderes Interface implementiert (selbst wenn alle Methoden vorhanden sind, und die Objekte somit die gesamte Funktionalität schon bereitstellen). In der Situation, dass der Programmierer keinen Zugriff auf den Quellcode der Klasse besitzt, ist eine Erweiterung nicht direkt möglich. Ein statisches Typsystem mit Breitensubtyping auf Objekten ermöglicht die selbe Flexibiliät wie Duck-Typing, bietet aber dennoch die Möglichkeit, Fehler zur Übersetzungszeit zu finden (falls Merkmale nicht dynamisch zur Laufzeit der Programms Objekten hinzugefügt werden sollen). Ein Beispiel für eine Programmiersprache, die Breitensubtyping auf Objekten unterstützt, ist Objective CAML.
[Bearbeiten] Beispiele
[Bearbeiten] Python
Wir betrachten eine von Bird abgeleitete Klasse Duck und eine Liste von Objekten, bei denen es sich nur teilweise um echte Enten (Instanzen der Duck-Klasse) handelt:
class Bird: # implizit von ''object'' abgeleitet "Vögel haben einen Namen, den sie in ihrer Stringdarstellung auch nennen" def __init__(self, name): self.name = name def __str__(self): return self.__class__.__name__+' '+self.name class Duck(Bird): "Enten sind Vögel, die außerdem quaken können" def quak(self): print str(self)+': quak' ducks = [Bird('Gustav'), Duck('Donald'), object()]
Wir haben also einen Vogel Gustav, der keine Ente ist, eine Ente Donald sowie ein sonstiges Objekt; Vogelobjekte geben als ihre String-Darstellung ihre Klasse sowie ihren Namen zurück. Die Ausführung von
for duck in ducks: try: duck.quak() except AttributeError: print 'Keine Ente:', duck
erzeugt die Ausgabe
Keine Ente: Bird Gustav Duck Donald: quak Keine Ente: <object object at 0x00A20468>
Dasselbe Ergebnis würde
for duck in ducks: if hasattr(duck, 'quak'): duck.quak() else: print 'Keine Ente:', duck
zeitigen; für das Duck-Typing entscheidend ist, dass wir die Klasse nicht (wie im folgenden Code) explizit überprüfen:
if isinstance(duck, Duck): duck.quak()
… sondern lediglich das Vorhandensein der relevanten Methode. Fügen wir jetzt eine Klasse Frog hinzu (auch Frösche können quaken), die mit Duck keine Verwandtschaftsbeziehung hat:
class Frog: def quak(self): print str(self)+': quak' ducks.append(Frog())
Wie die Ausgabe
Keine Ente: Bird Gustav Duck Donald: quak Keine Ente: <object object at 0x00A20468> <__main__.Frog instance at 0x00A886E8>: quak
zeigt, wird der Frosch als Ente akzeptiert – schließlich kann er quaken. Von Duck abgeleitet braucht er nicht zu sein.
Weitere Beispiele in Python sind StringIO-Objekte, die es erlauben, eine Zeichenkette wie eine Datei zu lesen, oder auch das Iterieren über die Zeilen einer Textdatei wie über die Elemente einer Liste.