Zum Inhalt springen

Duck-Typing

aus Wikipedia, der freien Enzyklopädie
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 26. Juni 2015 um 17:05 Uhr durch Xqt (Diskussion | Beiträge) (Beispiel in Python: dito). Sie kann sich erheblich von der aktuellen Version unterscheiden.

Duck-Typing ist ein Konzept der objektorientierten Programmierung, bei dem der Typ eines Objektes nicht durch seine Klasse beschrieben wird, sondern durch das Vorhandensein bestimmter Methoden oder Attribute.

Es handelt sich gewissermaßen um die Anwendung des Ententests in der Informatik, 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.”

„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.“

James Whitcomb Riley

Duck-Typing ist charakteristisch für objektorientierte Skriptsprachen wie Python, Groovy, PHP 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 D, sowie C# bis Version 3.0, 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 C++ bieten Funktionstemplates eine Art Ducktyping zur Kompilierzeit. Ältere GCC-Versionen boten daneben auch sogenannte Signatures an. Diese lassen sich wie Interfaces deklarieren und nutzen, sie sind jedoch unabhängig von der Klassenhierarchie, sodass beispielsweise für eine Ente nicht erneut deklariert werden muss, dass sie schnattern kann, also die Signature implementiert. Dies entspricht den Interface genannten Strukturen in Go.

Beispiel in 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(object):

    """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 ...>

Zum selben Ergebnis führt nachfolgender Code:

for duck in ducks:
    if hasattr(duck, 'quak'):
        duck.quak()
    else:
        print 'Keine Ente:', duck

Für das Duck-Typing entscheidend ist, dass wir lediglich das Vorhandensein der relevanten Methode überprüfen und nicht etwa (wie im folgenden Code) die Zugehörigkeit zu einer Klasse:

if isinstance(duck, Duck):
    duck.quak()

Fügen wir jetzt eine Klasse Frog hinzu (auch Frösche können quaken), die mit Duck keine Verwandtschaftsbeziehung hat:

class Frog(object):
    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 ...>
 <__main__.Frog instance at ...>: 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 oder über die Elemente einer Liste.

Siehe auch