[python] Qu'est-ce qu'un mixin, et pourquoi sont-ils utiles?



Answers

Tout d'abord, vous devez noter que les mixins existent uniquement dans les langages à plusieurs héritages. Vous ne pouvez pas faire un mixin en Java ou en 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 mixines ont généralement une portée étroite et ne sont pas destinées à être étendues.

[edit - 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 peut être du pattern de disposition . 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 Disposal extensible, vous pourriez vous épargner beaucoup de frappe supplémentaire.

[edit 2 - pour répondre à vos autres questions]

Qu'est-ce qui sépare un mixin de l'héritage multiple? Est-ce juste une question de sémantique?

Oui. La différence entre un mélange et un héritage multiple standard est juste une question de sémantique; une classe qui a plusieurs héritages peut utiliser un mix dans le cadre de cet héritage multiple.

Le but d'un mixin est de créer un type qui peut être "mélangé" à tout autre type via l'héritage sans affecter le type d'héritage 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 me développe principalement dans un langage qui ne les supporte pas, donc j'ai du mal à trouver un exemple décent qui suffira à fournir ce "ahah!" moment pour vous. Mais je vais essayer à nouveau. Je vais utiliser un exemple qui est artificiel - la plupart des langages fournissent déjà cette fonctionnalité d'une manière ou d'une autre - mais j'espère que cela expliquera comment les mixins sont censés être créés et utilisés. Voici:

Supposons que vous ayez un type que vous voulez pouvoir sérialiser vers et depuis XML. Vous voulez 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 permette 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, alors peut-être que vous utilisez un flux de fichier, ou une classe XML Writer de la bibliothèque d'exécution de votre langage ... peu importe. Le point est que vous voulez sérialiser votre objet en XML et récupérer un nouvel objet à partir de XML.

L'autre point important dans 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 voulez sérialiser, vous voulez des moyens génériques pour vous assurer que votre type va le faire et ça marche. Vous voulez la réutilisation de code.

Si votre langue le supporte, vous pouvez créer le mixin XmlSerializable pour faire votre travail pour vous. Ce type implémenterait les méthodes ToXML et FromXML. Il serait possible, en utilisant un mécanisme qui n'est pas important pour l'exemple, de rassembler toutes les données nécessaires à partir de n'importe quel type avec lequel construire le fragment XML retourné 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 qui doit être sérialisé en XML hérité de XmlSerializable. Chaque fois que vous deviez sérialiser ou désérialiser ce type, vous appeliez 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 document qui ne connaît rien à votre type d'origine, n'acceptant, disons, qu'un tableau de types XmlSerializable.

Imaginons maintenant d'utiliser ce scénario pour d'autres choses, comme créer un mixin qui assure que chaque classe qui le mélange enregistre chaque appel de méthode, ou un mixin qui fournit la transactionnalité au type qui le mélange. La liste peut s'allonger encore et encore.

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.

Espérons. :)

Question

Dans " Programming Python ", Mark Lutz mentionne "mixins". Je viens d'un arrière-plan C / C ++ / C # et je n'ai pas entendu le terme avant. Qu'est-ce qu'un mixin?

En lisant entre les lignes de cet exemple (auquel j'ai lié parce que c'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 préférable à 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?




Je pense à eux comme une manière disciplinée d'utiliser l'héritage multiple - parce que finalement un mixin est juste une autre classe python qui (pourrait) suivre les conventions sur les classes qui sont appelées mixins.

Ma compréhension des conventions qui régissent quelque chose que vous appelleriez un Mixin est un Mixin:

  • ajoute des méthodes mais pas des variables d'instance (les constantes de classe sont OK)
  • hérite seulement de l' 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 l'endroit où vous devez regarder (par rapport à l'héritage multiple complet). Ils sont similaires aux modules ruby.

Si je veux ajouter des variables d'instance (avec plus de flexibilité que ce qui est autorisé par un héritage simple) alors j'ai tendance à opter pour la composition.

Cela dit, j'ai vu des classes appelées XYZMixin qui ont des variables d'instance.




Je déconseille les mix-ins 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 juste les méthodes de correction de singe dans vos propres classes) qui n'est pas beaucoup plus effort.

Dans les classes à l'ancienne, vous pouvez utiliser des mix-ins pour saisir quelques méthodes d'une autre classe. Mais dans le monde du nouveau style, tout, même le mix-in, hérite de l' object . Cela signifie que toute utilisation de l'héritage multiple introduit naturellement des problèmes MRO .

Il existe des moyens de faire fonctionner le MRO à héritage multiple en Python, notamment la fonction super (), mais cela signifie que vous devez faire toute la hiérarchie de classe en utilisant super (), et il est beaucoup plus difficile de comprendre le flux de contrôle.




mixin permet 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 désirée. Bien que ruby ​​ne supporte pas l'héritage multiple, mais fournit mixin comme une alternative pour y parvenir.

Voici un exemple qui explique comment l'héritage multiple est réalisé en utilisant mixin.

module A    # you create a module
    def a1  # lets have a method 'a1' in it
    end
    def a2  # Another method 'a2'
    end
end

module B    # let's say we have another module
    def b1  # A method 'b1'
    end
    def b2  #another method b2
    end
end

class Sample    # we create a class 'Sample'
    include A   # including module 'A' in the class 'Sample' (mixin)
    include B   # including module B as well

    def S1      #class 'Sample' contains a method 's1'
    end
end

samp = Sample.new    # creating an instance object 'samp'

# we can access methods from module A and B in our class(power of mixin)

samp.a1     # accessing method 'a1' from module A
samp.a2     # accessing method 'a2' from module A
samp.b1     # accessing method 'b1' from module B
samp.b2     # accessing method 'a2' from module B
samp.s1     # accessing method 's1' inside the class Sample



Je pense qu'il y a eu quelques bonnes explications ici, mais je voulais donner un autre point de vue.

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 fusionnés pour créer un nouveau type de classe à hériter. En substance, vous n'héritez pas de plusieurs classes / mixins, mais plutôt, générez un nouveau type de classe avec toutes les propriétés du mixin à hériter. Cela a du sens puisque Scala est basé sur la JVM où l'héritage multiple n'est pas actuellement supporté (à partir de Java 8). Ce type de classe mixin, en passant, est un type spécial appelé Trait in Scala.

Il est fait allusion à la façon dont une classe est définie: class NewClass étend FirstMixin avec SecondMixin avec ThirdMixin ...

Je ne sais pas si l'interpréteur CPython fait la même chose (mixin class-composition) mais je ne serais pas surpris. Aussi, venant d'un fond C ++, je n'appellerais pas un ABC ou une 'interface' équivalente à un mixin - c'est un concept similaire mais divergent dans l'utilisation et l'implémentation.




Peut-être qu'un exemple de ruby ​​peut aider:

Vous pouvez inclure le mixin Comparable et définir une fonction "<=>(other)" , le mixin fournit toutes ces fonctions:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

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 si l' instance est plus grande que l' other et plus de 0 si l' other est plus grand.




J'ai lu que vous avez un arrière-plan ac #. Un bon point de départ pourrait donc être une implémentation de mixin pour .NET.

Vous pouvez consulter le projet codeplex sur http://remix.codeplex.com/

Regardez le lien du Symposium lang.net pour avoir un aperçu. Il y a encore plus à venir sur la documentation sur la page codeplex.

ce qui concerne Stefan




Links