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:
Ist eine Mehrfachvererbung notwendig oder nicht, um ein Mixin zu charakterisieren?
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 ==
:
class ComparableMixin(object):
"""This class has methods which use `<=` and `==`,
but this class does NOT implement those methods."""
def __ne__(self, other):
return not (self == other)
def __lt__(self, other):
return self <= other and (self != other)
def __gt__(self, other):
return not self <= other
def __ge__(self, other):
return self == other or self > other
class Integer(ComparableMixin):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o
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:
import functools
@functools.total_ordering
class Integer(object):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
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:
class HasMethod1(object):
def method(self):
return 1
class HasMethod2(object):
def method(self):
return 2
class UsesMethod10(object):
def usesMethod(self):
return self.method() + 10
class UsesMethod20(object):
def usesMethod(self):
return self.method() + 20
class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass
assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22
# Nothing prevents implementing the method
# on the base class like in Definition 1:
class C3_10(UsesMethod10):
def method(self):
return 3
assert C3_10().usesMethod() == 13
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:
- Geräte
__next__
- erbt von einer einzelnen Klasse
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ögen Set
und als Iterator
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