Diese Antwort zielt darauf ab, Mixins zu erklären mit Beispielen die sind:
-
Eigenständig Kurz und bündig: Sie müssen keine Bibliotheken kennen, 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 eine Python Thema.
Sie wird sich auch mit der umstrittenen Frage befassen:
Ist 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 2 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, welche davon richtig ist.
Der Konsens kann in den verschiedenen Sprachen unterschiedlich sein.
Definition 1: keine Mehrfachvererbung
Ein Mixin ist eine Klasse, bei der eine Methode der Klasse eine Methode verwendet, die nicht in der Klasse definiert ist.
Daher soll die Klasse nicht instanziiert werden, sondern vielmehr als Basisklasse dienen. Andernfalls würde die Instanz über Methoden verfügen, die nicht aufgerufen werden können, ohne eine Ausnahme auszulösen.
Eine Einschränkung, die einige Quellen hinzufügen, ist, dass die Klasse keine Daten, sondern nur Methoden enthalten darf, aber ich sehe 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 von nur <=
y ==
:
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 spezielle Beispiel könnte durch die functools.total_ordering()
Dekorateur, 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 die von eine weitere Basisklasse und nicht durch die Ableitung wie in Definition 1.
Der Begriff Mixin-Klasse bezieht sich auf Basisklassen, die für die Verwendung in diesem Entwurfsmuster vorgesehen sind (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 in der abgeleiteten Klasse implementiert sein, in diesem Fall sind wir wieder bei Definition 1. Man muss die Intentionen des Autors berücksichtigen.
Dieses Muster ist interessant, weil es möglich ist, Funktionalitäten mit verschiedenen Basisklassen 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
Maßgebliche Python-Vorkommen
En el Offizielles Dokument für Sammlungen.abc In der Dokumentation wird ausdrücklich der Begriff Mixin-Methoden .
Sie besagt, dass wenn eine Klasse:
- implementiert
__next__
- erbt von einer einzigen Klasse
Iterator
dann erhält die Klasse eine __iter__
Mixin-Methode umsonst.
Also zumindest zu diesem Punkt der Dokumentation, mixin erfordert keine Mehrfachvererbung und ist kohärent mit Definition 1.
Die Dokumentation könnte natürlich an verschiedenen Stellen widersprüchlich sein, und andere wichtige Python-Bibliotheken könnten in ihrer Dokumentation die andere Definition verwenden.
Auf dieser Seite wird auch der Begriff Set mixin
was eindeutig darauf hindeutet, dass Klassen wie Set
y Iterator
können Mixin-Klassen genannt werden.
In anderen Sprachen
-
Rubin: Offensichtlich ist keine Mehrfachvererbung für Mixin erforderlich, wie in den wichtigsten Referenzbüchern wie Ruby programmieren und die Programmiersprache Ruby
-
C++: A virtual
Methode, die eingestellt ist =0
ist eine rein virtuelle Methode.
Definition 1 stimmt mit der Definition einer abstrakten Klasse überein (eine Klasse, die eine rein virtuelle Methode hat). Diese Klasse kann nicht instanziiert werden.
Definition 2 ist mit virtueller Vererbung möglich: Mehrfachvererbung von zwei abgeleiteten Klassen