Ich bin beim Lesen von zufälligen Themen über Software online auf den Begriff Entenschreiben gestoßen und habe ihn nicht vollständig verstanden.
Was ist "Ententyping"?
Ich bin beim Lesen von zufälligen Themen über Software online auf den Begriff Entenschreiben gestoßen und habe ihn nicht vollständig verstanden.
Was ist "Ententyping"?
Antworten:
Es ist ein Begriff, der in dynamischen Sprachen verwendet wird , die keine starke Typisierung aufweisen .
Die Idee ist, dass Sie keinen Typ benötigen, um eine vorhandene Methode für ein Objekt aufzurufen. Wenn eine Methode darauf definiert ist, können Sie sie aufrufen.
Der Name kommt von der Phrase "Wenn es wie eine Ente aussieht und wie eine Ente quakt, ist es eine Ente".
Wikipedia hat viel mehr Informationen.
Ententypisierung bedeutet, dass eine Operation die Anforderungen, die ihre Operanden erfüllen müssen, nicht formal spezifiziert , sondern sie nur mit dem Gegebenen ausprobiert.
Anders als andere gesagt haben, bezieht sich dies nicht unbedingt auf dynamische Sprachen oder Vererbungsprobleme.
Beispielaufgabe: Rufen Sie eine Methode Quack
für ein Objekt auf.
Ohne Ententypisierung muss eine Funktion f
, die diese Aufgabe ausführt, im Voraus angeben, dass ihr Argument eine Methode unterstützen muss Quack
. Ein üblicher Weg ist die Verwendung von Schnittstellen
interface IQuack {
void Quack();
}
void f(IQuack x) {
x.Quack();
}
Der Aufruf f(42)
schlägt fehl, f(donald)
funktioniert jedoch, solange donald
es sich um eine Instanz eines IQuack
Untertyps handelt.
Ein anderer Ansatz ist die strukturelle Typisierung - aber auch hier wird die Methode Quack()
formal spezifiziert. Alles, was nicht quack
im Voraus beweisen kann , führt zu einem Compilerfehler.
def f(x : { def Quack() : Unit }) = x.Quack()
Wir könnten sogar schreiben
f :: Quackable a => a -> IO ()
f = quack
in Haskell, wo die Quackable
Typklasse die Existenz unserer Methode sicherstellt.
Nun, wie gesagt, ein Enten-Typisierungssystem spezifiziert keine Anforderungen, sondern versucht nur, ob etwas funktioniert .
Daher verwendet ein dynamisches Typsystem wie Pythons immer die Ententypisierung:
def f(x):
x.Quack()
Wenn f
ein x
unterstützendes a Quack()
angezeigt wird, ist alles in Ordnung. Wenn nicht, stürzt es zur Laufzeit ab.
Das Tippen von Enten impliziert jedoch überhaupt kein dynamisches Tippen. Tatsächlich gibt es einen sehr beliebten, aber vollständig statischen Ansatz zum Tippen von Enten, der auch keine Anforderungen stellt:
template <typename T>
void f(T x) { x.Quack(); }
Die Funktion sagt in keiner Weise, dass sie etwas will x
, das kann Quack
, also versucht sie stattdessen nur die Kompilierungszeit und wenn alles funktioniert, ist es in Ordnung.
def f(x)
statt def f(IQuack x)
.
Die Diskussion der Semantik der Frage ist ziemlich nuanciert (und sehr akademisch), aber hier ist die allgemeine Idee:
Ententippen
("Wenn es wie eine Ente geht und wie eine Ente quakt, dann ist es eine Ente.") - JA! aber was heißt das ??! Dies lässt sich am besten anhand eines Beispiels veranschaulichen:
Beispiele für Enten-Typisierungsfunktionen:
Stellen Sie sich vor, ich habe einen Zauberstab. Es hat besondere Kräfte. Wenn ich mit dem Zauberstab schwinge und "Drive!" zu einem Auto, na dann fährt es!
Funktioniert es bei anderen Dingen? Ich bin mir nicht sicher: Also versuche ich es auf einem LKW. Wow - es fährt auch! Ich probiere es dann in Flugzeugen, Zügen und 1 Woods aus (sie sind eine Art Golfschläger, mit dem die Leute einen Golfball "fahren"). Sie fahren alle!
Aber würde es beispielsweise bei einer Teetasse funktionieren? Fehler: KAAAA-BOOOOOOM! das hat nicht so gut geklappt. ====> Teetassen können nicht fahren !! duh!?
Dies ist im Grunde das Konzept der Ententypisierung. Es ist ein Try-Before-You-Buy- System. Wenn es funktioniert, ist alles in Ordnung. Aber wenn es fehlschlägt, wie eine Granate, die noch in Ihrer Hand ist, wird es in Ihrem Gesicht explodieren.
Mit anderen Worten, wir interessieren uns eher für das, was das Objekt kann , als für das, was das Objekt ist .
Beispiel: statisch typisierte Sprachen
Wenn wir uns mit dem befassten, was das Objekt tatsächlich war , funktioniert unser Zaubertrick nur bei voreingestellten, autorisierten Typen - in diesem Fall Autos -, aber bei anderen Objekten, die fahren können : Lastwagen, Mopeds, Tuk-Tuks usw. Es funktioniert nicht auf Lastwagen, weil unser Zauberstab erwartet, dass es nur auf Autos funktioniert .
Mit anderen Worten, in diesem Szenario untersucht der Zauberstab sehr genau, was das Objekt ist (ist es ein Auto?), Und nicht, was das Objekt tun kann (z. B. ob Autos, Lastwagen usw. fahren können).
Die einzige Möglichkeit, einen LKW zum Fahren zu bringen, besteht darin, den Zauberstab dazu zu bringen, sowohl LKWs als auch Autos zu erwarten (möglicherweise durch "Implementieren einer gemeinsamen Schnittstelle"). Wenn Sie nicht wissen, was das bedeutet, ignorieren Sie es einfach für den Moment.
Zusammenfassung: Schlüssel zum Mitnehmen
Was beim Entenschreiben wichtig ist, ist, was das Objekt tatsächlich kann und nicht, was das Objekt ist .
Angenommen, Sie entwerfen eine einfache Funktion, die ein Objekt vom Typ Bird
abruft und dessen walk()
Methode aufruft . Es gibt zwei Ansätze, die Sie sich vorstellen können:
Bird
, sonst wird ihr Code nicht kompiliert. Wenn jemand meine Funktion nutzen möchte, muss er sich bewusst sein, dass ich nur Bird
s akzeptiereobjects
und ich rufe einfach die walk()
Methode des Objekts auf . Also, wenn die object
Dose walk()
es richtig ist, wenn es nicht kann, wird meine Funktion fehlschlagen. Hier ist es also nicht wichtig, dass das Objekt ein Bird
oder etwas anderes ist, es ist wichtig, dass es kann walk()
(Dies ist Ententypisierung ).Es muss berücksichtigt werden, dass die Ententypisierung in einigen Fällen nützlich sein kann, zum Beispiel verwendet Python häufig die Ententypisierung .
Wikipedia hat eine ziemlich detaillierte Erklärung:
http://en.wikipedia.org/wiki/Duck_typing
Die Ententypisierung ist eine Art der dynamischen Typisierung, bei der die aktuellen Methoden und Eigenschaften eines Objekts die gültige Semantik bestimmen und nicht die Vererbung von einer bestimmten Klasse oder Implementierung einer bestimmten Schnittstelle.
Der wichtige Hinweis ist wahrscheinlich, dass sich ein Entwickler beim Enten-Tippen mehr mit den Teilen des Objekts befasst, die verbraucht werden, als mit dem tatsächlichen zugrunde liegenden Typ.
Ich sehe viele Antworten, die die alte Redewendung wiederholen:
Wenn es wie eine Ente aussieht und wie eine Ente quakt, ist es eine Ente
und dann tauchen Sie ein in eine Erklärung, was Sie mit dem Tippen von Enten tun können, oder in ein Beispiel, das das Konzept weiter zu verschleiern scheint.
Ich finde nicht so viel Hilfe.
Dies ist der beste Versuch, eine einfache englische Antwort über das Tippen von Enten zu finden, die ich gefunden habe:
Ententypisierung bedeutet, dass ein Objekt durch das definiert wird, was es kann, nicht durch das, was es ist.
Dies bedeutet, dass wir uns weniger mit der Klasse / dem Typ eines Objekts befassen als vielmehr damit, welche Methoden darauf aufgerufen werden können und welche Operationen daran ausgeführt werden können. Wir kümmern uns nicht um den Typ, wir kümmern uns darum, was er kann .
Ententippen:
Wenn es spricht und geht wie eine Ente, dann ist es eine Ente
Dies wird typischerweise als Entführung bezeichnet ( abduktives Denken oder auch als Rückführung bezeichnet , eine klarere Definition, denke ich):
Aus C (Schlussfolgerung, was wir sehen ) und R (Regel, was wir wissen ) akzeptieren / entscheiden / übernehmen wir P (Prämisse, Eigentum ) mit anderen Worten eine gegebene Tatsache an
... die Grundlage der medizinischen Diagnose
mit Enten: C = geht, redet , R = wie eine Ente , P = es ist eine Ente
Zurück zur Programmierung:
Objekt o hat Methode / Eigenschaft mp1 und Schnittstelle / Typ T benötigt / definiert mp1
Objekt o hat Methode / Eigenschaft mp2 und Schnittstelle / Typ T benötigt / definiert mp2
...
Also mehr als nur akzeptieren mp1 ... für ein Objekt, solange es eine Definition von mp1 ... erfüllt , sollte Compiler / Laufzeit auch mit der Behauptung in Ordnung sein, dass o vom Typ T ist
Und nun, ist es bei den obigen Beispielen der Fall? Ist das Tippen von Enten im Wesentlichen überhaupt kein Tippen? Oder sollten wir es implizite Eingabe nennen?
Ein Blick auf die Sprache selbst kann hilfreich sein. es hilft mir oft (ich bin kein englischer Muttersprachler).
Im duck typing
:
1) Das Wort typing
bedeutet nicht, auf einer Tastatur zu tippen (wie es das beständige Bild in meinem Kopf war), sondern zu bestimmen, " was für ein Ding ist das?" "
2) das Wort duck
drückt aus, wie diese Bestimmung durchgeführt wird; Es ist eine Art "lose" Bestimmung, wie in: " Wenn es wie eine Ente geht ... dann ist es eine Ente ". Es ist "locker", weil das Ding eine Ente sein kann oder nicht, aber ob es tatsächlich eine Ente ist, spielt keine Rolle; Was zählt ist, dass ich damit machen kann, was ich mit Enten machen kann und Verhaltensweisen von Enten erwarte. Ich kann es mit Brotkrumen füttern und das Ding kann auf mich zugehen oder mich angreifen oder sich zurückziehen ... aber es wird mich nicht verschlingen, wie es ein Grizzly tun würde.
Ich weiß, dass ich keine allgemeine Antwort gebe. In Ruby deklarieren wir nicht die Arten von Variablen oder Methoden - alles ist nur eine Art Objekt. Die Regel lautet also "Klassen sind keine Typen".
In Ruby ist die Klasse niemals (OK, fast nie) der Typ. Stattdessen wird der Typ eines Objekts mehr durch die Möglichkeiten dieses Objekts definiert. In Ruby nennen wir das Ententippen. Wenn ein Objekt wie eine Ente läuft und wie eine Ente spricht, behandelt der Dolmetscher es gerne so, als wäre es eine Ente.
Beispielsweise schreiben Sie möglicherweise eine Routine, um einer Zeichenfolge Songinformationen hinzuzufügen. Wenn Sie aus einem C # - oder Java-Hintergrund stammen, könnten Sie versucht sein, Folgendes zu schreiben:
def append_song(result, song)
# test we're given the right parameters
unless result.kind_of?(String)
fail TypeError.new("String expected") end
unless song.kind_of?(Song)
fail TypeError.new("Song expected")
end
result << song.title << " (" << song.artist << ")" end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Umfassen Sie Rubys Ententipp, und Sie würden etwas viel Einfacheres schreiben:
def append_song(result, song)
result << song.title << " (" << song.artist << ")"
end
result = ""
append_song(result, song) # => "I Got Rhythm (Gene Kelly)"
Sie müssen den Typ der Argumente nicht überprüfen. Wenn sie << (im Fall des Ergebnisses) oder Titel und Künstler (im Fall des Liedes) unterstützen, funktioniert einfach alles. Wenn dies nicht der Fall ist, löst Ihre Methode ohnehin eine Ausnahme aus (genau wie dies der Fall gewesen wäre, wenn Sie die Typen überprüft hätten). Aber ohne die Prüfung ist Ihre Methode plötzlich viel flexibler. Sie könnten ihm ein Array, eine Zeichenfolge, eine Datei oder ein anderes Objekt übergeben, das mit << angehängt wird, und es würde einfach funktionieren.
Duck Typing ist kein Type Hinting!
Grundsätzlich verwenden Sie zur Verwendung der "Ententypisierung" nicht einen bestimmten Typ, sondern einen größeren Bereich von Untertypen (ohne Vererbung, wenn ich Untertypen meine, "Dinge", die in dieselben Profile passen), indem Sie eine gemeinsame Schnittstelle verwenden .
Sie können sich ein System vorstellen, das Informationen speichert. Zum Schreiben / Lesen von Informationen benötigen Sie eine Art Speicher und Informationen.
Arten des Speichers können sein: Datei, Datenbank, Sitzung usw.
Die Schnittstelle informiert Sie über die verfügbaren Optionen (Methoden) unabhängig vom Speichertyp, sodass an dieser Stelle nichts implementiert ist! Mit anderen Worten, die Schnittstelle weiß nichts darüber, wie Informationen gespeichert werden.
Jedes Speichersystem muss die Existenz der Schnittstelle kennen, indem es dieselben Methoden implementiert.
interface StorageInterface
{
public function write(string $key, array $value): bool;
public function read(string $key): array;
}
class File implements StorageInterface
{
public function read(string $key): array {
//reading from a file
}
public function write(string $key, array $value): bool {
//writing in a file implementation
}
}
class Session implements StorageInterface
{
public function read(string $key): array {
//reading from a session
}
public function write(string $key, array $value): bool {
//writing in a session implementation
}
}
class Storage implements StorageInterface
{
private $_storage = null;
function __construct(StorageInterface $storage) {
$this->_storage = $storage;
}
public function read(string $key): array {
return $this->_storage->read($key);
}
public function write(string $key, array $value): bool {
return ($this->_storage->write($key, $value)) ? true : false;
}
}
Jedes Mal, wenn Sie Informationen schreiben / lesen müssen:
$file = new Storage(new File());
$file->write('filename', ['information'] );
echo $file->read('filename');
$session = new Storage(new Session());
$session->write('filename', ['information'] );
echo $session->read('filename');
In diesem Beispiel verwenden Sie Duck Typing im Speicherkonstruktor:
function __construct(StorageInterface $storage) ...
Hoffe es hat geholfen;)
Ich denke, es ist verwirrt, dynamisches Tippen, statisches Tippen und Ententippen zu verwechseln. Das Tippen von Enten ist ein eigenständiges Konzept, und selbst eine statisch typisierte Sprache wie Go könnte ein Typprüfsystem haben, das das Tippen von Enten implementiert. Wenn ein Typsystem die Methoden eines (deklarierten) Objekts überprüft, jedoch nicht den Typ, kann dies als Entensprachsprache bezeichnet werden.
Ich versuche, den berühmten Satz auf meine Weise zu verstehen: "Python kümmert sich nicht darum, ob ein Objekt eine echte Ente ist oder nicht. Es ist nur wichtig, ob das Objekt, erstens 'Quacksalber', zweitens 'wie eine Ente'."
Es gibt eine gute Website. http://www.voidspace.org.uk/python/articles/duck_typing.shtml#id14
Der Autor wies darauf hin, dass Sie mit der Eingabe von Enten Ihre eigenen Klassen erstellen können, die eine eigene interne Datenstruktur haben - auf die jedoch mit normaler Python-Syntax zugegriffen wird.