Cette réponse a pour but d'expliquer mixin avec des exemples qui sont:
autonome: bref, sans besoin de connaître toutes les bibliothèques de comprendre l'exemple.
-
en Python, pas dans d'autres langues.
Il est compréhensible qu'il y avait des exemples dans d'autres langues telles que le Rubis, car le terme est beaucoup plus commun dans ces langues, mais c'est un Python fil.
Il doit également prendre en compte la question controversée:
Est l'héritage multiple ou pas?
Définitions
Je n'ai pas encore de voir une citation à partir d'une "autorité" source disant clairement ce qu'est un mixin en Python.
J'ai vu 2 définitions possibles d'un mixin (si ils sont considérés comme différents des autres concepts tels que les classes de base abstraites), et les gens n'ont pas tout à fait d'accord sur ce qui est correct.
Le consensus peut varier entre les différentes langues.
Définition 1: pas d'héritage multiple
Un mixin est une classe telle que certains la méthode de la classe utilise une méthode qui n'est pas définie dans la classe.
Par conséquent, la classe n'est pas destiné à être instancié, mais plutôt servir de classe de base. Sinon, l'instance aurait méthodes qui ne peut pas être appelé sans lever d'exception.
Une contrainte dont certaines sources ajouter, c'est que la classe ne peut pas contenir de données, seulement les méthodes, mais je ne vois pas pourquoi cela est nécessaire. Dans la pratique, cependant, de nombreux mixin n'avez pas toutes les données, et les classes de base sans les données sont plus simples à utiliser.
Un exemple classique est la mise en œuvre de tous les opérateurs de comparaison à partir de seulement <=
et ==
:
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
Cet exemple en particulier, pourrait avoir été réalisé par l' functools.total_ordering()
décorateur, mais le jeu ici est de réinventer la roue:
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)
Définition 2: l'héritage multiple
Un mixin est un modèle de conception dans laquelle une méthode d'une classe de base utilise une méthode qu'il ne définit pas, et que la méthode est destinée à être mise en œuvre par une autre classe de base, et non pas par le dérivé comme dans la Définition 1.
Le terme mixin classe fait référence à des classes de base qui sont destinés à être utilisés dans ce modèle de conception (TODO ceux qui utilisent la méthode, ou ceux qui mettent en œuvre?)
Il n'est pas facile de décider si une classe donnée est un mixin ou pas: la méthode pourrait être mis en œuvre sur la classe dérivée, dans ce cas, nous sommes de retour à la Définition 1. Vous devez considérer les intentions d'auteur.
Ce modèle est intéressant car il est possible de se recombiner les fonctionnalités avec différents choix de classes de base:
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
Autorité Python occurrences
À l' officiel documentatiton pour les collections.abc de la documentation utilise explicitement le terme Mixin Méthodes.
Il stipule que si une classe:
- implémente
__next__
- hérite d'une classe unique
Iterator
ensuite, la classe devient un __iter__
mixin méthode pour gratuit.
Par conséquent, au moins sur ce point de la documentation, mixin ne nécessite pas l'héritage multiple, et qui est cohérent avec la Définition 1.
La documentation pourrait être contradictoire à différents points, et d'autres bibliothèques Python peut-être à l'aide de l'autre définition dans leur documentation.
Cette page utilise également le terme Set mixin
, ce qui laisse clairement entendre que des classes comme l' Set
et Iterator
peut être appelé Mixin classes.
Dans d'autres langues
Ruby: de toute évidence, ne nécessite pas l'héritage multiple pour mixin, comme mentionné dans les principaux ouvrages de référence tels que la Programmation Ruby et Le Langage de programmation Ruby
-
C++: Une méthode qui n'est pas mis en œuvre est une méthode virtuelle pure.
Définition 1 coïncide avec la définition d'une classe abstraite (une classe qui a une méthode virtuelle pure).
Cette classe ne peut pas être instanciée.
Définition 2 n'est pas possible, puisqu'il n'est pas possible de mettre en œuvre des méthodes virtuelles pures à partir d'autres classes de base en C++.