In " Programming Python " erwähnt Mark Lutz "Mixins". Ich komme aus C / C ++ / C # und habe den Begriff noch nicht gehört. Was ist ein Mixin?
Wenn ich zwischen den Zeilen dieses Beispiels lese (auf das ich verlinkt habe, weil es ziemlich lang ist), gehe ich davon aus, dass es sich um die Verwendung der Mehrfachvererbung handelt, um eine Klasse zu erweitern, im Gegensatz zur 'richtigen' Unterklasse. Ist das richtig?
Warum sollte ich das tun wollen, anstatt die neue Funktionalität in eine Unterklasse zu stellen? Warum sollte ein Mixin / Multiple-Vererbungs-Ansatz besser sein als die Verwendung von Komposition?
Was unterscheidet ein Mixin von Mehrfachvererbung? Ist es nur eine Frage der Semantik?
quelle
Parent
Klasse undChild1
,Child2
,ChildN
Unterklassen innerhalb einer 3rd - Party - Bibliothek, und Sie wollen ein individuelles Verhalten für die ganze Familie. Idealerweise möchten Sie ein solches Verhalten hinzufügenParent
und hoffen, dass der Bibliotheksentwickler eines Drittanbieters Ihre Pull-Anfrage entgegennimmt. Andernfalls müssen Sie Ihre eigenen implementierenclass NewBehaviorMixin
und dann einen vollständigen Satz von Wrapper-Klassen wieclass NewParent(NewBehaviorMixin, Parent): pass
undclass NewChildN(NewBehaviorMixin, ChildN): pass
usw. definieren. (PS: Kennen Sie einen besseren Weg?)Zunächst sollten Sie beachten, dass Mixins nur in Sprachen mit Mehrfachvererbung vorhanden sind. Sie können in Java oder C # kein Mixin erstellen.
Grundsätzlich ist ein Mixin ein eigenständiger Basistyp, der eine eingeschränkte Funktionalität und polymorphe Resonanz für eine Kinderklasse bietet. Wenn Sie in C # denken, denken Sie an eine Schnittstelle, die Sie nicht implementieren müssen, da sie bereits implementiert ist. Sie erben einfach davon und profitieren von seiner Funktionalität.
Mixins haben normalerweise einen engen Umfang und sind nicht dazu gedacht, erweitert zu werden.
[bearbeiten - warum:]
Ich nehme an, ich sollte mich mit dem Warum befassen, da Sie gefragt haben. Der große Vorteil ist, dass Sie es nicht immer wieder selbst tun müssen. In C # könnte der größte Ort, an dem ein Mixin profitieren könnte, das Entsorgungsmuster sein . Wann immer Sie IDisposable implementieren, möchten Sie fast immer dem gleichen Muster folgen, aber am Ende schreiben und schreiben Sie den gleichen Basiscode mit geringfügigen Abweichungen neu. Wenn es ein erweiterbares Entsorgungsmixin gäbe, könnten Sie sich viel zusätzliches Tippen sparen.
[Bearbeiten 2 - um Ihre anderen Fragen zu beantworten]
Ja. Der Unterschied zwischen einem Mixin und einer Standard-Mehrfachvererbung ist nur eine Frage der Semantik. Eine Klasse mit Mehrfachvererbung verwendet möglicherweise ein Mixin als Teil dieser Mehrfachvererbung.
Der Sinn eines Mixins besteht darin, einen Typ zu erstellen, der über die Vererbung in jeden anderen Typ "eingemischt" werden kann, ohne den ererbenden Typ zu beeinflussen, und dennoch einige nützliche Funktionen für diesen Typ bietet.
Stellen Sie sich erneut eine Schnittstelle vor, die bereits implementiert ist.
Ich persönlich verwende keine Mixins, da ich mich hauptsächlich in einer Sprache entwickle, die sie nicht unterstützt. Daher fällt es mir wirklich schwer, ein anständiges Beispiel zu finden, das nur das "ahah!" Moment für dich. Aber ich werde es noch einmal versuchen. Ich werde ein Beispiel verwenden, das erfunden wurde - die meisten Sprachen bieten die Funktion bereits auf die eine oder andere Weise an -, aber das wird hoffentlich erklären, wie Mixins erstellt und verwendet werden sollen. Hier geht:
Angenommen, Sie haben einen Typ, den Sie in und aus XML serialisieren möchten. Sie möchten, dass der Typ eine "ToXML" -Methode bereitstellt, die eine Zeichenfolge zurückgibt, die ein XML-Fragment mit den Datenwerten des Typs enthält, und eine "FromXML" -Methode, mit der der Typ seine Datenwerte aus einem XML-Fragment in einer Zeichenfolge rekonstruieren kann. Auch dies ist ein erfundenes Beispiel. Vielleicht verwenden Sie einen Dateistream oder eine XML Writer-Klasse aus der Laufzeitbibliothek Ihrer Sprache ... was auch immer. Der Punkt ist, dass Sie Ihr Objekt in XML serialisieren und ein neues Objekt aus XML zurückerhalten möchten.
Der andere wichtige Punkt in diesem Beispiel ist, dass Sie dies generisch tun möchten. Sie möchten nicht für jeden Typ, den Sie serialisieren möchten, eine "ToXML" - und eine "FromXML" -Methode implementieren müssen. Sie möchten generische Mittel, um sicherzustellen, dass Ihr Typ dies tut und es einfach funktioniert. Sie möchten die Wiederverwendung von Code.
Wenn Ihre Sprache dies unterstützt, können Sie das XmlSerializable-Mixin erstellen, um Ihre Arbeit für Sie zu erledigen. Dieser Typ würde die Methoden ToXML und FromXML implementieren. Mithilfe eines Mechanismus, der für das Beispiel nicht wichtig ist, kann es alle erforderlichen Daten von jedem Typ erfassen, mit dem es gemischt ist, um das von ToXML zurückgegebene XML-Fragment zu erstellen, und es kann diese Daten auch wiederherstellen, wenn FromXML vorhanden ist namens.
Und das ist es. Um es zu verwenden, müssten Sie jeden Typ, der in XML serialisiert werden muss, von XmlSerializable erben. Wann immer Sie diesen Typ serialisieren oder deserialisieren mussten, riefen Sie einfach ToXML oder FromXML auf. Da XmlSerializable ein vollwertiger und polymorpher Typ ist, können Sie möglicherweise einen Dokumentenserialisierer erstellen, der nichts über Ihren ursprünglichen Typ weiß und beispielsweise nur ein Array von XmlSerializable-Typen akzeptiert.
Stellen Sie sich nun vor, Sie verwenden dieses Szenario für andere Zwecke, z. B. zum Erstellen eines Mixins, das sicherstellt, dass jede Klasse, die es einmischt, jeden Methodenaufruf protokolliert, oder als Mixin, das dem Typ, der es einmischt, Transaktionsfähigkeit verleiht. Die Liste kann weiter und weiter gehen.
Wenn Sie sich ein Mixin nur als einen kleinen Basistyp vorstellen, der einem Typ eine kleine Menge an Funktionalität hinzufügen soll, ohne diesen Typ anderweitig zu beeinflussen, dann sind Sie golden.
Hoffnungsvoll. :) :)
quelle
Diese Antwort zielt darauf ab, Mixins anhand von Beispielen zu erklären :
in sich geschlossen : kurz, ohne dass Sie Bibliotheken kennen müssen, um das Beispiel zu verstehen.
in Python , nicht in anderen Sprachen.
Es ist verständlich, dass es Beispiele aus anderen Sprachen wie Ruby gab, da der Begriff in diesen Sprachen viel häufiger vorkommt, aber dies ist ein Python- Thread.
Es wird auch die kontroverse Frage berücksichtigt:
Definitionen
Ich habe noch kein Zitat aus einer "maßgeblichen" Quelle gesehen, das klar sagt, was ein Mixin in Python ist.
Ich habe zwei mögliche Definitionen eines Mixins gesehen (wenn sie sich von anderen ähnlichen Konzepten wie abstrakten Basisklassen unterscheiden sollen), und die Leute sind sich nicht ganz einig, welches richtig ist.
Der Konsens kann zwischen verschiedenen Sprachen variieren.
Definition 1: keine Mehrfachvererbung
Ein Mixin ist eine Klasse, bei der eine Methode der Klasse eine Methode verwendet, die in der Klasse nicht definiert ist.
Daher soll die Klasse nicht instanziiert werden, sondern als Basisklasse dienen. Andernfalls verfügt die Instanz über Methoden, die nicht aufgerufen werden können, ohne eine Ausnahme auszulösen.
Eine Einschränkung, die einige Quellen hinzufügen, ist, dass die Klasse möglicherweise keine Daten enthält, sondern nur Methoden, aber ich verstehe nicht, warum dies notwendig ist. In der Praxis haben jedoch viele nützliche Mixins keine Daten, und Basisklassen ohne Daten sind einfacher zu verwenden.
Ein klassisches Beispiel ist die Implementierung aller Vergleichsoperatoren nur von
<=
und==
:Dieses besondere Beispiel hätte über den
functools.total_ordering()
Dekorateur erreicht werden können, aber hier ging es darum, das Rad neu zu erfinden:Definition 2: Mehrfachvererbung
Ein Mixin ist ein Entwurfsmuster, bei dem eine Methode einer Basisklasse eine Methode verwendet, die sie nicht definiert, und von der diese Methode implementiert werden soll anderen Basisklasse , nicht von der in Definition 1 abgeleiteten.
Der Begriff Mixin-Klasse bezieht sich auf Basisklassen, die in diesem Entwurfsmuster verwendet werden sollen (TODO diejenigen, die die Methode verwenden, oder diejenigen, die sie implementieren?).
Es ist nicht einfach zu entscheiden, ob eine bestimmte Klasse ein Mixin ist oder nicht: Die Methode könnte nur für die abgeleitete Klasse implementiert werden. In diesem Fall kehren wir zu Definition 1 zurück. Sie müssen die Absichten des Autors berücksichtigen.
Dieses Muster ist interessant, weil es möglich ist, Funktionalitäten mit verschiedenen Auswahlmöglichkeiten von Basisklassen neu zu kombinieren:
Autorisierende Python-Vorkommen
In der offiziellen Dokumentation für Sammlungen.abc wird in der Dokumentation ausdrücklich der Begriff Mixin-Methoden verwendet .
Es heißt, wenn eine Klasse:
__next__
Iterator
dann bekommt die Klasse eine
__iter__
Mixin-Methode kostenlose .Zumindest in diesem Punkt der Dokumentation erfordert Mixin daher keine Mehrfachvererbung und mit Definition 1 überein.
Die Dokumentation kann natürlich an verschiedenen Stellen widersprüchlich sein, und andere wichtige Python-Bibliotheken verwenden möglicherweise die andere Definition in ihrer Dokumentation.
Auf dieser Seite wird auch der Begriff verwendet
Set mixin
, der eindeutig darauf hinweist, dass Klassen Mixin-Klassen mögenSet
und alsIterator
solche bezeichnet werden können.In anderen Sprachen
Ruby: Es ist klar, dass für das Mixin keine Mehrfachvererbung erforderlich ist, wie in wichtigen Nachschlagewerken wie Programming Ruby und The Ruby Programming Language erwähnt
C ++: Eine nicht implementierte Methode ist eine rein virtuelle Methode.
Definition 1 stimmt mit der Definition einer abstrakten Klasse überein (eine Klasse mit einer rein virtuellen Methode). Diese Klasse kann nicht instanziiert werden.
Definition 2 ist mit virtueller Vererbung möglich: Mehrfachvererbung von zwei abgeleiteten Klassen
quelle
Ich betrachte sie als eine disziplinierte Methode zur Verwendung der Mehrfachvererbung - denn letztendlich ist ein Mixin nur eine weitere Python-Klasse, die (möglicherweise) den Konventionen über Klassen folgt, die Mixins genannt werden.
Mein Verständnis der Konventionen, die etwas regeln, das Sie als Mixin bezeichnen würden, ist das eines Mixins:
object
(in Python)Auf diese Weise wird die potenzielle Komplexität der Mehrfachvererbung begrenzt, und es ist relativ einfach, den Ablauf Ihres Programms zu verfolgen, indem Sie einschränken, wo Sie suchen müssen (im Vergleich zur vollständigen Mehrfachvererbung). Sie ähneln Ruby-Modulen .
Wenn ich Instanzvariablen hinzufügen möchte (mit mehr Flexibilität als bei der Einzelvererbung), tendiere ich zur Komposition.
Trotzdem habe ich Klassen namens XYZMixin gesehen, die Instanzvariablen haben.
quelle
Mixins ist ein Konzept in der Programmierung, bei dem die Klasse Funktionen bereitstellt, jedoch nicht zur Instanziierung verwendet werden soll. Der Hauptzweck von Mixins besteht darin, eigenständige Funktionen bereitzustellen. Es ist am besten, wenn die Mixins selbst keine Vererbung mit anderen Mixins aufweisen und auch den Zustand vermeiden. In Sprachen wie Ruby gibt es eine direkte Sprachunterstützung, für Python jedoch keine. Sie können jedoch die Vererbung mehrerer Klassen verwenden, um die in Python bereitgestellten Funktionen auszuführen.
Ich habe dieses Video gesehen http://www.youtube.com/watch?v=v_uKI2NOLEM , um die Grundlagen von Mixins zu verstehen. Für Anfänger ist es sehr nützlich, die Grundlagen von Mixins und deren Funktionsweise sowie die Probleme bei der Implementierung zu verstehen.
Wikipedia ist immer noch das Beste: http://en.wikipedia.org/wiki/Mixin
quelle
Ein Mixin ist eine begrenzte Form der Mehrfachvererbung. In einigen Sprachen unterscheidet sich der Mechanismus zum Hinzufügen eines Mixins zu einer Klasse geringfügig (in Bezug auf die Syntax) von dem der Vererbung.
Insbesondere im Kontext von Python ist ein Mixin eine übergeordnete Klasse, die Unterklassen Funktionen bietet, jedoch nicht selbst instanziiert werden soll.
Was Sie dazu veranlassen könnte zu sagen, "das ist nur Mehrfachvererbung, nicht wirklich ein Mixin", ist, wenn die Klasse, die für ein Mixin verwechselt werden könnte, tatsächlich instanziiert und verwendet werden kann - es ist also tatsächlich ein semantischer und sehr realer Unterschied.
Beispiel für Mehrfachvererbung
Dieses Beispiel aus der Dokumentation ist ein OrderedCounter:
Es werden sowohl das
Counter
als auch dasOrderedDict
vomcollections
Modul untergeordnet.Beide
Counter
undOrderedDict
sollen instanziiert und alleine verwendet werden. Indem wir beide unterordnen, können wir jedoch einen Zähler haben, der geordnet ist und den Code in jedem Objekt wiederverwendet.Dies ist eine leistungsstarke Methode zur Wiederverwendung von Code, kann jedoch auch problematisch sein. Wenn sich herausstellt, dass eines der Objekte einen Fehler enthält, kann durch sorgfältiges Beheben ein Fehler in der Unterklasse entstehen.
Beispiel eines Mixins
Mixins werden normalerweise als Weg zur Wiederverwendung von Code ohne potenzielle Kopplungsprobleme beworben, die eine kooperative Mehrfachvererbung wie der OrderedCounter haben könnte. Wenn Sie Mixins verwenden, verwenden Sie Funktionen, die nicht so eng mit den Daten verbunden sind.
Im Gegensatz zum obigen Beispiel ist ein Mixin nicht für die alleinige Verwendung vorgesehen. Es bietet neue oder andere Funktionen.
Beispielsweise enthält die Standardbibliothek einige Mixins in der
socketserver
Bibliothek .In diesem Fall überschreiben die Mixin-Methoden die Methoden in der
UDPServer
Objektdefinition, um Parallelität zu ermöglichen.Die überschriebene Methode scheint zu sein
process_request
und bietet auch eine andere Methodeprocess_request_thread
. Hier ist es aus dem Quellcode :Ein erfundenes Beispiel
Dies ist ein Mixin, das hauptsächlich zu Demonstrationszwecken dient. Die meisten Objekte werden sich über den Nutzen dieses Repräsentanten hinaus entwickeln:
und Verwendung wäre:
Und Verwendung:
quelle
Ich denke, hier gab es einige gute Erklärungen, aber ich wollte eine andere Perspektive bieten.
In Scala können Sie Mixins ausführen, wie hier beschrieben wurde. Sehr interessant ist jedoch, dass die Mixins tatsächlich zusammengeführt werden, um eine neue Art von Klasse zu erstellen, von der geerbt werden soll. Im Wesentlichen erben Sie nicht von mehreren Klassen / Mixins, sondern generieren eine neue Art von Klasse mit allen Eigenschaften des Mixins, von dem geerbt werden soll. Dies ist sinnvoll, da Scala auf der JVM basiert, bei der Mehrfachvererbung derzeit nicht unterstützt wird (ab Java 8). Dieser Mixin-Klassentyp ist übrigens ein spezieller Typ, der in Scala als Merkmal bezeichnet wird.
Es wird in der Art und Weise angedeutet, wie eine Klasse definiert wird: Klasse NewClass erweitert FirstMixin mit SecondMixin mit ThirdMixin ...
Ich bin mir nicht sicher, ob der CPython-Interpreter dasselbe tut (Mixin-Class-Komposition), aber ich wäre nicht überrascht. Aus einem C ++ - Hintergrund stammend, würde ich auch kein ABC oder "Interface" nennen, das einem Mixin entspricht - es ist ein ähnliches Konzept, aber unterschiedlich in Verwendung und Implementierung.
quelle
Ich würde von Mix-Ins in neuem Python-Code abraten, wenn Sie einen anderen Weg finden (z. B. Komposition statt Vererbung oder nur Methoden zum Patchen von Affen in Ihre eigenen Klassen), der nicht viel mehr ist Anstrengung.
In Klassen alten Stils können Sie Mix-Ins verwenden, um einige Methoden aus einer anderen Klasse abzurufen. Aber in der Welt des neuen Stils erbt alles, sogar das Mix-In
object
. Das bedeutet, dass jede Verwendung der Mehrfachvererbung natürlich zu MRO-Problemen führt .Es gibt Möglichkeiten, MRO mit Mehrfachvererbung in Python zum Laufen zu bringen, insbesondere die Funktion super (). Dies bedeutet jedoch, dass Sie Ihre gesamte Klassenhierarchie mit super () ausführen müssen, und es ist erheblich schwieriger, den Kontrollfluss zu verstehen.
quelle
Vielleicht helfen ein paar Beispiele.
Wenn Sie eine Klasse erstellen und möchten, dass sie sich wie ein Wörterbuch verhält, können Sie alle
__ __
erforderlichen Methoden definieren . Aber das ist ein bisschen schmerzhaft. Alternativ können Sie nur einige definieren und (zusätzlich zu jeder anderen Vererbung) vonUserDict.DictMixin
(verschoben nach ) erbencollections.DictMixin
in py3k verschoben) erben. Dies hat zur Folge, dass automatisch der gesamte Rest der Wörterbuch-API definiert wird.Ein zweites Beispiel: Mit dem GUI-Toolkit wxPython können Sie Listensteuerelemente mit mehreren Spalten erstellen (z. B. die Dateianzeige im Windows Explorer). Standardmäßig sind diese Listen ziemlich einfach. Sie können zusätzliche Funktionen hinzufügen, z. B. die Möglichkeit, die Liste nach einer bestimmten Spalte zu sortieren, indem Sie auf die Spaltenüberschrift klicken, von ListCtrl erben und entsprechende Mixins hinzufügen.
quelle
Es ist kein Python-Beispiel, aber in der Programmiersprache D
mixin
bezieht sich der Begriff auf ein Konstrukt, das auf die gleiche Weise verwendet wird. einer Klasse einen Haufen Zeug hinzufügen.In D (was übrigens kein MI macht) wird dies durch Einfügen einer Vorlage (denken Sie an syntaktisch bewusste und sichere Makros und Sie werden nah dran sein) in einen Bereich gemacht. Dies ermöglicht es einer einzelnen Codezeile in einer Klasse, Struktur, Funktion, einem Modul oder was auch immer, auf eine beliebige Anzahl von Deklarationen erweitert zu werden.
quelle
OP erwähnte, dass er / sie noch nie von Mixin in C ++ gehört hat, vielleicht weil sie in C ++ als CRTP (Curiously Recurring Template Pattern) bezeichnet werden. Außerdem erwähnte @Ciro Santilli, dass Mixin über eine abstrakte Basisklasse in C ++ implementiert wird. Während abstrakte Basisklassen zum Implementieren von Mixin verwendet werden können, ist dies ein Overkill, da die Funktionalität der virtuellen Funktion zur Laufzeit mithilfe der Vorlage zur Kompilierungszeit erreicht werden kann, ohne dass der Aufwand für die Suche nach virtuellen Tabellen zur Laufzeit anfällt.
Das CRTP-Muster wird hier ausführlich beschrieben
Ich habe das Python-Beispiel in der Antwort von @Ciro Santilli mithilfe der folgenden Vorlagenklasse in C ++ konvertiert:
BEARBEITEN: In ComparableMixin wurde ein geschützter Konstruktor hinzugefügt, sodass er nur vererbt und nicht instanziiert werden kann. Das Beispiel wurde aktualisiert, um zu zeigen, wie ein geschützter Konstruktor beim Erstellen eines Objekts von ComparableMixin einen Kompilierungsfehler verursacht.
quelle
Vielleicht kann ein Beispiel von Ruby helfen:
Sie können das Mixin einschließen
Comparable
und eine Funktion definieren"<=>(other)"
. Das Mixin bietet alle diese Funktionen:Dies geschieht durch Aufrufen
<=>(other)
und Zurückgeben des richtigen Ergebnisses."instance <=> other"
Gibt 0 zurück, wenn beide Objekte gleich sind, weniger als 0, wenn sieinstance
größer als sind,other
und mehr als 0, wenn sieother
größer sind.quelle
__lt__
stattdessen als Basis definiert wird__cmp__
, wird letzterer tatsächlich veraltet und von der Verwendung abgeraten. Mir scheint es einfacher , dass mixin zu verwenden , anstatt ziemlich kompliziert Dekorateure (Teil functools ) - obwohl dies eine Lage sein kann , mehr dynamisch zu reagieren auf denen Vergleiche sind ...Mit mixin können Sie einer Klasse Funktionen hinzufügen, dh Sie können mit in einem Modul definierten Methoden interagieren, indem Sie das Modul in die gewünschte Klasse aufnehmen. Ruby unterstützt zwar keine Mehrfachvererbung, bietet aber als Alternative Mixin an, um dies zu erreichen.
Hier ist ein Beispiel, das erklärt, wie Mehrfachvererbung mit Mixin erreicht wird.
quelle
Ich habe gerade ein Python-Mixin verwendet, um Unit-Tests für Python-Milters durchzuführen. Normalerweise spricht ein Milter mit einem MTA, was das Testen von Einheiten schwierig macht. Das Testmixin überschreibt Methoden, die mit dem MTA kommunizieren, und erstellt stattdessen eine simulierte Umgebung, die von Testfällen gesteuert wird.
Sie nehmen also eine unveränderte Milter-Anwendung wie spfmilter und mischen TestBase wie folgt:
Verwenden Sie dann TestMilter in den Testfällen für die Milter-Anwendung:
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
quelle
Ich denke, frühere Antworten haben sehr gut definiert, was MixIns sind. Um sie besser zu verstehen, kann es jedoch nützlich sein, MixIns mit abstrakten Klassen und Schnittstellen aus der Code- / Implementierungsperspektive zu vergleichen :
1. Abstrakte Klasse
Klasse , die eine oder mehrere abstrakte Methoden enthalten muss
Die abstrakte Klasse kann Status- (Instanzvariablen) und nicht abstrakte Methoden enthalten
2. Schnittstelle
3. MixIns
In zB Python sind dies nur Konventionen, da alle oben genannten als
class
es definiert sind . Das gemeinsame Merkmal von Abstract Classes, Interfaces und MixIns ist jedoch, dass sie nicht alleine existieren sollten, dh nicht instanziiert werden sollten.quelle
Ich habe gelesen, dass Sie einen AC # Hintergrund haben. Ein guter Ausgangspunkt könnte also eine Mixin-Implementierung für .NET sein.
Vielleicht möchten Sie das Codeplex-Projekt unter http://remix.codeplex.com/ überprüfen.
Sehen Sie sich den Link zum lang.net-Symposium an, um sich einen Überblick zu verschaffen. Die Dokumentation auf der Codeplex-Seite enthält noch weitere Informationen.
Grüße Stefan
quelle