Dans " Programmation Python ", Mark Lutz mentionne les "mixins". Je viens d'un milieu C / C ++ / C # et je n'ai jamais entendu le terme auparavant. Qu'est-ce qu'un mixin?
En lisant entre les lignes de cet exemple (auquel j'ai lié parce qu'il est assez long), je suppose qu'il s'agit d'utiliser l'héritage multiple pour étendre une classe par opposition à un sous-classement «correct». Est-ce correct?
Pourquoi voudrais-je faire cela plutôt que de mettre la nouvelle fonctionnalité dans une sous-classe? D'ailleurs, pourquoi une approche mixin / héritage multiple serait-elle meilleure que l'utilisation de la composition?
Qu'est-ce qui sépare un mixin de l'héritage multiple? Est-ce juste une question de sémantique?
la source
Parent
classes etChild1
, des sousChild2
-ChildN
classes dans une bibliothèque tierce, et vous souhaitez un comportement personnalisé pour toute la famille. Idéalement, vous souhaitez ajouter un tel comportement àParent
, et espérons que le développeur de bibliothèque tiers prendra votre demande Pull. Sinon, vous devrez implémenter la vôtreclass NewBehaviorMixin
, puis définir un ensemble complet de classes wrapper telles queclass NewParent(NewBehaviorMixin, Parent): pass
andclass NewChildN(NewBehaviorMixin, ChildN): pass
, etc. (PS: Connaissez-vous une meilleure façon?)Tout d'abord, vous devez noter que les mixins n'existent que dans les langages à héritage multiple. Vous ne pouvez pas faire de mixage en Java ou C #.
Fondamentalement, un mixin est un type de base autonome qui offre une fonctionnalité limitée et une résonance polymorphe pour une classe enfant. Si vous pensez en C #, pensez à une interface que vous n'avez pas à implémenter car elle est déjà implémentée; vous en héritez et profitez de ses fonctionnalités.
Les mixins ont généralement une portée étroite et ne sont pas destinés à être étendus.
[modifier - pourquoi:]
Je suppose que je devrais expliquer pourquoi, puisque vous avez demandé. Le gros avantage est que vous n'avez pas à le faire vous-même encore et encore. En C #, le plus grand endroit où un mixin pourrait bénéficier pourrait être du modèle d'élimination . Chaque fois que vous implémentez IDisposable, vous voulez presque toujours suivre le même modèle, mais vous finissez par écrire et réécrire le même code de base avec des variations mineures. S'il y avait un mixage d'élimination extensible, vous pourriez vous épargner beaucoup de frappe supplémentaire.
[modifier 2 - pour répondre à vos autres questions]
Oui. La différence entre un mixin et l'héritage multiple standard n'est qu'une question de sémantique; une classe qui a un héritage multiple peut utiliser un mixin dans le cadre de cet héritage multiple.
Le point d'un mixin est de créer un type qui peut être "mélangé" à n'importe quel autre type via l'héritage sans affecter le type héritant tout en offrant des fonctionnalités bénéfiques pour ce type.
Encore une fois, pensez à une interface déjà implémentée.
Personnellement, je n'utilise pas de mixins car je développe principalement dans un langage qui ne les prend pas en charge, donc j'ai vraiment du mal à trouver un exemple décent qui fournira juste ce "ahah!" moment pour vous. Mais je vais réessayer. Je vais utiliser un exemple qui est artificiel - la plupart des langues fournissent déjà la fonctionnalité d'une manière ou d'une autre - mais qui, espérons-le, expliquera comment les mixins sont censés être créés et utilisés. Voici:
Supposons que vous ayez un type que vous souhaitez pouvoir sérialiser vers et depuis XML. Vous souhaitez que le type fournisse une méthode "ToXML" qui renvoie une chaîne contenant un fragment XML avec les valeurs de données du type, et un "FromXML" qui permet au type de reconstruire ses valeurs de données à partir d'un fragment XML dans une chaîne. Encore une fois, ceci est un exemple artificiel, donc vous utilisez peut-être un flux de fichiers ou une classe XML Writer de la bibliothèque d'exécution de votre langue ... peu importe. Le fait est que vous voulez sérialiser votre objet en XML et récupérer un nouvel objet depuis XML.
L'autre point important de cet exemple est que vous voulez le faire de manière générique. Vous ne voulez pas avoir à implémenter une méthode "ToXML" et "FromXML" pour chaque type que vous souhaitez sérialiser, vous voulez des moyens génériques pour vous assurer que votre type le fera et que cela fonctionne. Vous voulez réutiliser le code.
Si votre langue le supportait, vous pourriez créer le mixin XmlSerializable pour faire votre travail pour vous. Ce type implémenterait les méthodes ToXML et FromXML. Il serait, en utilisant un mécanisme qui n'est pas important pour l'exemple, capable de rassembler toutes les données nécessaires à partir de n'importe quel type avec lequel il est mélangé pour créer le fragment XML renvoyé par ToXML et il serait également capable de restaurer ces données lorsque FromXML est appelé.
Et c'est tout. Pour l'utiliser, vous auriez tout type devant être sérialisé en XML hérité de XmlSerializable. Chaque fois que vous avez besoin de sérialiser ou de désérialiser ce type, vous appelez simplement ToXML ou FromXML. En fait, étant donné que XmlSerializable est un type à part entière et polymorphe, vous pourriez concevoir un sérialiseur de documents qui ne sait rien de votre type d'origine, acceptant uniquement, disons, un tableau de types XmlSerializable.
Imaginez maintenant utiliser ce scénario pour d'autres choses, comme la création d'un mixin qui garantit que chaque classe qui le mélange dans les journaux de chaque appel de méthode, ou un mixin qui fournit une transactionnalité au type qui le mélange. La liste peut continuer indéfiniment.
Si vous pensez simplement à un mixin comme un petit type de base conçu pour ajouter une petite quantité de fonctionnalités à un type sans affecter autrement ce type, alors vous êtes en or.
J'espère. :)
la source
Cette réponse vise à expliquer les mixins avec des exemples qui sont:
autonome : bref, sans avoir besoin de connaître aucune bibliothèque pour comprendre l'exemple.
en Python , pas dans d'autres langues.
Il est compréhensible qu'il y ait eu des exemples provenant d'autres langages tels que Ruby puisque le terme est beaucoup plus courant dans ces langages, mais il s'agit d'un thread Python .
Il examinera également la question controversée:
Définitions
Je n'ai pas encore vu de citation d'une source "faisant autorité" disant clairement ce qu'est un mixin en Python.
J'ai vu 2 définitions possibles d'un mixin (si elles doivent être considérées comme différentes d'autres concepts similaires tels que les classes de base abstraites), et les gens ne sont pas entièrement d'accord sur celui qui est correct.
Le consensus peut varier entre différentes langues.
Définition 1: pas d'héritage multiple
Un mixin est une classe telle qu'une 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ée à être instanciée, mais plutôt à servir de classe de base. Sinon, l'instance aurait des méthodes qui ne peuvent pas être appelées sans déclencher une exception.
Une contrainte que certaines sources ajoutent est que la classe peut ne pas contenir de données, uniquement des méthodes, mais je ne vois pas pourquoi cela est nécessaire. Cependant, dans la pratique, de nombreux mixins utiles n'ont pas de données et les classes de base sans données sont plus simples à utiliser.
Un exemple classique est l'implémentation de tous les opérateurs de comparaison à partir de
<=
et uniquement==
:Cet exemple particulier aurait pu être réalisé via le
functools.total_ordering()
décorateur, mais le jeu ici était de réinventer la roue:Définition 2: héritage multiple
Un mixin est un modèle de conception dans lequel une méthode d'une classe de base utilise une méthode qu'elle ne définit pas, et cette méthode est destinée à être implémentée par une autre classe de base , pas par le dérivé comme dans la définition 1.
Le terme classe de mixage fait référence aux classes de base qui sont destinées à être utilisées dans ce modèle de conception (TODO celles qui utilisent la méthode ou celles qui la mettent en œuvre?)
Il n'est pas facile de décider si une classe donnée est un mixin ou non: la méthode pourrait être simplement implémentée sur la classe dérivée, auquel cas nous revenons à la Définition 1. Vous devez considérer les intentions de l'auteur.
Ce schéma est intéressant car il est possible de recombiner des fonctionnalités avec différents choix de classes de base:
Occurrences Python faisant autorité
Dans la documentation officielle de collections.abc, la documentation utilise explicitement le terme Méthodes Mixin .
Il indique que si une classe:
__next__
Iterator
alors la classe obtient gratuitement une
__iter__
méthode de mixage .Par conséquent, au moins sur ce point de la documentation, mixin ne nécessite pas d'héritage multiple et est cohérent avec la définition 1.
La documentation pourrait bien sûr être contradictoire à différents points, et d'autres bibliothèques Python importantes pourraient utiliser l'autre définition dans leur documentation.
Cette page utilise également le terme
Set mixin
, ce qui suggère clairement que des classes commeSet
etIterator
peuvent être appelées classes Mixin.Dans d'autres langues
Ruby: Clairement ne nécessite pas d'héritage multiple pour mixin, comme mentionné dans les principaux livres de référence tels que Programming Ruby et The Ruby Programming Language
C ++: Une méthode qui n'est pas implémentée est une méthode virtuelle pure.
La 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.
La définition 2 est possible avec l'héritage virtuel: héritage multiple de deux classes dérivées
la source
Je les considère comme une manière disciplinée d'utiliser l'héritage multiple - parce qu'en fin de compte, un mixin n'est qu'une autre classe python qui (pourrait) suivre les conventions sur les classes appelées mixins.
Ma compréhension des conventions qui régissent ce que vous appelleriez un Mixin est qu'un Mixin:
object
(en Python)De cette façon, il limite la complexité potentielle de l'héritage multiple et facilite le suivi du flux de votre programme en limitant où vous devez regarder (par rapport à l'héritage multiple complet). Ils sont similaires aux modules rubis .
Si je veux ajouter des variables d'instance (avec plus de flexibilité que ne le permet l'héritage unique), j'ai tendance à opter pour la composition.
Cela dit, j'ai vu des classes appelées XYZMixin qui ont des variables d'instance.
la source
Mixins est un concept de programmation dans lequel la classe fournit des fonctionnalités mais n'est pas destiné à être utilisé pour l'instanciation. L'objectif principal de Mixins est de fournir des fonctionnalités autonomes et il serait préférable que les mixins eux-mêmes n'aient pas d'héritage avec d'autres mixins et évitent également l'état. Dans des langages tels que Ruby, il existe une prise en charge directe des langues, mais pour Python, ce n'est pas le cas. Cependant, vous pouvez utiliser l'héritage multi-classes pour exécuter les fonctionnalités fournies en Python.
J'ai regardé cette vidéo http://www.youtube.com/watch?v=v_uKI2NOLEM pour comprendre les bases des mixins. Il est très utile pour un débutant de comprendre les bases des mixins et comment ils fonctionnent et les problèmes que vous pourriez rencontrer lors de leur mise en œuvre.
Wikipedia est toujours le meilleur: http://en.wikipedia.org/wiki/Mixin
la source
Un mixin est une forme limitée d'héritage multiple. Dans certains langages, le mécanisme pour ajouter un mixin à une classe est légèrement différent (en termes de syntaxe) de celui de l'héritage.
Dans le contexte de Python en particulier, un mixin est une classe parente qui fournit des fonctionnalités aux sous-classes mais n'est pas destinée à être instanciée elle-même.
Ce qui pourrait vous amener à dire, "c'est juste un héritage multiple, pas vraiment un mixage", c'est si la classe qui pourrait être confondue pour un mixage peut en fait être instanciée et utilisée - donc c'est en fait une différence sémantique et très réelle.
Exemple d'héritage multiple
Cet exemple, extrait de la documentation , est un OrderedCounter:
Il sous-classe à la fois le
Counter
et leOrderedDict
ducollections
module.Les deux
Counter
etOrderedDict
sont destinés à être instanciés et utilisés seuls. Cependant, en les sous-classant tous les deux, nous pouvons avoir un compteur qui est ordonné et réutilise le code dans chaque objet.C'est un moyen puissant de réutiliser le code, mais cela peut aussi être problématique. S'il s'avère qu'il y a un bogue dans l'un des objets, le corriger sans soin pourrait créer un bogue dans la sous-classe.
Exemple de mixin
Les mixins sont généralement présentés comme le moyen d'obtenir la réutilisation du code sans problèmes de couplage potentiels que l'héritage multiple coopératif, comme le OrderedCounter, pourrait avoir. Lorsque vous utilisez des mixins, vous utilisez des fonctionnalités qui ne sont pas aussi étroitement couplées aux données.
Contrairement à l'exemple ci-dessus, un mixin n'est pas destiné à être utilisé seul. Il fournit des fonctionnalités nouvelles ou différentes.
Par exemple, la bibliothèque standard a quelques mixins dans la
socketserver
bibliothèque .Dans ce cas, les méthodes mixin remplacent les méthodes de la
UDPServer
définition d'objet pour autoriser la concurrence.La méthode surchargée semble être
process_request
et il fournit également une autre méthode,process_request_thread
. Le voici à partir du code source :Un exemple artificiel
Ceci est un mixin qui est principalement à des fins de démonstration - la plupart des objets évolueront au-delà de l'utilité de cette repr:
et l'utilisation serait:
Et l'utilisation:
la source
Je pense qu'il y a eu de bonnes explications ici, mais je voulais apporter une autre perspective.
Dans Scala, vous pouvez faire des mixins comme cela a été décrit ici, mais ce qui est très intéressant, c'est que les mixins sont en fait «fusionnés» ensemble pour créer un nouveau type de classe dont il peut hériter. En substance, vous n'héritez pas de plusieurs classes / mixins, mais générez plutôt un nouveau type de classe avec toutes les propriétés du mixin dont vous devez hériter. Cela est logique puisque Scala est basé sur la JVM où l'héritage multiple n'est pas actuellement pris en charge (à partir de Java 8). Ce type de classe mixin, soit dit en passant, est un type spécial appelé Trait in Scala.
Il est fait allusion à la façon dont une classe est définie: la classe NewClass étend FirstMixin avec SecondMixin avec ThirdMixin ...
Je ne sais pas si l'interpréteur CPython fait de même (mixin class-composition) mais je ne serais pas surpris. De plus, venant d'un arrière-plan C ++, je n'appellerais pas un ABC ou une `` interface '' équivalente à un mixin - c'est un concept similaire mais divergent dans l'utilisation et la mise en œuvre.
la source
Je déconseille les mélanges dans le nouveau code Python, si vous pouvez trouver un autre moyen de le contourner (comme la composition au lieu de l'héritage, ou simplement des méthodes de correction de singe dans vos propres classes) qui ne sont pas beaucoup plus effort.
Dans les classes à l'ancienne, vous pouvez utiliser des mix-ins pour récupérer quelques méthodes d'une autre classe. Mais dans le monde du nouveau style, tout, même le mixage, hérite de
object
. Cela signifie que toute utilisation de l'héritage multiple introduit naturellement des problèmes de MRO .Il existe des moyens de faire fonctionner MRO à héritage multiple en Python, notamment la fonction super (), mais cela signifie que vous devez faire toute la hiérarchie de votre classe en utilisant super (), et il est beaucoup plus difficile de comprendre le flux de contrôle.
la source
Peut-être que quelques exemples vous aideront.
Si vous créez une classe et que vous souhaitez qu'elle agisse comme un dictionnaire, vous pouvez définir toutes les différentes
__ __
méthodes nécessaires. Mais c'est un peu pénible. Vous pouvez également en définir quelques-uns et hériter (en plus de tout autre héritage) deUserDict.DictMixin
(déplacé verscollections.DictMixin
dans py3k). Cela aura pour effet de définir automatiquement tout le reste de l'api du dictionnaire.Un deuxième exemple: la boîte à outils GUI wxPython vous permet de créer des contrôles de liste avec plusieurs colonnes (comme, par exemple, l'affichage du fichier dans l'Explorateur Windows). Par défaut, ces listes sont assez basiques. Vous pouvez ajouter des fonctionnalités supplémentaires, telles que la possibilité de trier la liste par une colonne particulière en cliquant sur l'en-tête de la colonne, en héritant de ListCtrl et en ajoutant des mixins appropriés.
la source
Ce n'est pas un exemple Python mais dans le langage de programmation D, le terme
mixin
est utilisé pour désigner une construction utilisée de la même manière; ajouter un tas de trucs à une classe.Dans D (qui d'ailleurs ne fait pas MI), cela se fait en insérant un modèle (pensez aux macros syntaxiquement conscientes et sûres et vous serez proche) dans une portée. Cela permet à une seule ligne de code dans une classe, une structure, une fonction, un module ou quoi que ce soit d'étendre à n'importe quel nombre de déclarations.
la source
OP mentionne qu'il / elle n'a jamais entendu parler de mixin en C ++, peut-être parce qu'ils sont appelés Curieusement Recurrent Template Pattern (CRTP) en C ++. De plus, @Ciro Santilli a mentionné que le mixin est implémenté via une classe de base abstraite en C ++. Bien que la classe de base abstraite puisse être utilisée pour implémenter le mixage, c'est une exagération car la fonctionnalité de la fonction virtuelle au moment de l'exécution peut être obtenue en utilisant un modèle au moment de la compilation sans la surcharge de la recherche de table virtuelle au moment de l'exécution.
Le modèle CRTP est décrit en détail ici
J'ai converti l'exemple python dans la réponse de @Ciro Santilli en C ++ en utilisant la classe de modèle ci-dessous:
EDIT: Ajout d'un constructeur protégé dans ComparableMixin afin qu'il ne puisse être hérité que et non instancié. Mise à jour de l'exemple pour montrer comment le constructeur protégé provoquera une erreur de compilation lorsqu'un objet de ComparableMixin est créé.
la source
Peut-être qu'un exemple de rubis peut aider:
Vous pouvez inclure le mixin
Comparable
et définir une fonction"<=>(other)"
, le mixin fournit toutes ces fonctions:Il le fait en invoquant
<=>(other)
et en redonnant le bon résultat."instance <=> other"
renvoie 0 si les deux objets sont égaux, moins de 0 siinstance
est plus grand queother
et plus de 0 siother
est plus grand.la source
__lt__
comme base au lieu de__cmp__
, cette dernière est en fait obsolète et déconseillée à utiliser. Il me semble plus simple d'utiliser ce mix au lieu de décorateurs assez compliqués (faisant partie de functools ) - bien que celui-ci puisse réagir plus dynamiquement sur quelles comparaisons sont fournies ...mixin donne un moyen d'ajouter des fonctionnalités dans une classe, c'est-à-dire que vous pouvez interagir avec les méthodes définies dans un module en incluant le module dans la classe souhaitée. Bien que ruby ne supporte pas l'héritage multiple, mais fournit une mixin comme alternative pour y parvenir.
voici un exemple qui explique comment l'héritage multiple est réalisé en utilisant mixin.
la source
Je viens d'utiliser un mixin python pour implémenter des tests unitaires pour les milters python. Normalement, une discussion plus douce avec un MTA rend les tests unitaires difficiles. Le mixage de test remplace les méthodes qui communiquent avec le MTA et créent à la place un environnement simulé piloté par des cas de test.
Donc, vous prenez une application Milter non modifiée, comme spfmilter, et mixin TestBase, comme ceci:
Ensuite, utilisez TestMilter dans les cas de test pour l'application Milter:
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
la source
Je pense que les réponses précédentes ont très bien défini ce que sont les MixIns . Cependant, afin de mieux les comprendre, il pourrait être utile de comparer les MixIns avec les classes abstraites et les interfaces du point de vue code / implémentation:
1. Classe abstraite
Classe qui doit contenir une ou plusieurs méthodes abstraites
La classe abstraite peut contenir des méthodes d'état (variables d'instance) et non abstraites
2. Interface
3. MixIns
Dans Python par exemple, ce ne sont que des conventions, car tout ce qui précède est défini comme
class
es. Cependant, la caractéristique commune des classes abstraites, des interfaces et des MixIns est qu'elles ne devraient pas exister par elles-mêmes, c'est-à-dire qu'elles ne devraient pas être instanciées.la source
J'ai lu que vous avez des antécédents en AC #. Un bon point de départ pourrait donc être une implémentation mixin pour .NET.
Vous voudrez peut-être consulter le projet codeplex à http://remix.codeplex.com/
Regardez le lien du symposium lang.net pour obtenir un aperçu. Il y a encore plus à venir sur la documentation sur la page codeplex.
en ce qui concerne Stefan
la source