En " Programación de Python ", Mark Lutz menciona "mixins". Soy de un fondo C / C ++ / C # y no he escuchado el término antes. ¿Qué es un mixin?
Leyendo entre las líneas de este ejemplo (al que me he vinculado porque es bastante largo), supongo que es un caso de usar herencia múltiple para extender una clase en lugar de una subclase 'adecuada'. ¿Es esto correcto?
¿Por qué querría hacer eso en lugar de poner la nueva funcionalidad en una subclase? Para el caso, ¿por qué sería mejor un enfoque de herencia mixin / múltiple que usar composición?
¿Qué separa una mezcla de herencia múltiple? ¿Es solo una cuestión de semántica?
fuente
Parent
clase yChild1
,Child2
,ChildN
subclases dentro de una biblioteca tercera parte, y se desea un comportamiento personalizado para toda la familia. Idealmente, le gustaría agregar ese comportamientoParent
y esperar que el desarrollador de la biblioteca de terceros tome su solicitud de extracción. De lo contrario, tendrá que implementar el suyo propioclass NewBehaviorMixin
y luego definir un conjunto completo de clases de contenedor comoclass NewParent(NewBehaviorMixin, Parent): pass
yclass NewChildN(NewBehaviorMixin, ChildN): pass
, etc. (PD: ¿Conoce una mejor manera?)Primero, debe tener en cuenta que los mixins solo existen en lenguajes de herencia múltiple. No puedes hacer una mezcla en Java o C #.
Básicamente, un mixin es un tipo de base independiente que proporciona funcionalidad limitada y resonancia polimórfica para una clase infantil. Si está pensando en C #, piense en una interfaz que no tiene que implementar realmente porque ya está implementada; simplemente heredas de él y te beneficias de su funcionalidad.
Las mixinas son típicamente de alcance estrecho y no están destinadas a extenderse.
[editar - en cuanto a por qué:]
Supongo que debería abordar por qué, ya que lo preguntaste. El gran beneficio es que no tiene que hacerlo usted mismo una y otra vez. En C #, el lugar más grande donde un mixin podría beneficiarse podría ser el patrón de eliminación . Cada vez que implementa IDisposable, casi siempre desea seguir el mismo patrón, pero termina escribiendo y reescribiendo el mismo código básico con pequeñas variaciones. Si hubiera una mezcla de eliminación extensible, podría ahorrarse una gran cantidad de tipeo adicional.
[editar 2 - para responder a sus otras preguntas]
Si. La diferencia entre un mixin y una herencia múltiple estándar es solo una cuestión de semántica; una clase que tiene herencia múltiple podría utilizar un mixin como parte de esa herencia múltiple.
El objetivo de un mixin es crear un tipo que se pueda "mezclar" con cualquier otro tipo a través de la herencia sin afectar el tipo de herencia y al mismo tiempo ofrecer alguna funcionalidad beneficiosa para ese tipo.
Nuevamente, piense en una interfaz que ya está implementada.
Personalmente no uso mixins, ya que me desarrollo principalmente en un lenguaje que no los admite, por lo que me está costando mucho encontrar un ejemplo decente que solo proporcione ese "¡ajá!" momento para ti Pero lo intentaré de nuevo. Voy a usar un ejemplo que es artificial: la mayoría de los idiomas ya proporcionan la función de una forma u otra, pero eso, con suerte, explicará cómo se supone que se deben crear y usar mixins. Aquí va:
Supongamos que tiene un tipo que desea poder serializar hacia y desde XML. Desea que el tipo proporcione un método "ToXML" que devuelve una cadena que contiene un fragmento XML con los valores de datos del tipo y un "FromXML" que permite que el tipo reconstruya sus valores de datos a partir de un fragmento XML en una cadena. Una vez más, este es un ejemplo artificial, por lo que quizás use una secuencia de archivos o una clase de Escritor XML de la biblioteca de tiempo de ejecución de su idioma ... lo que sea. El punto es que desea serializar su objeto a XML y recuperar un nuevo objeto de XML.
El otro punto importante en este ejemplo es que desea hacer esto de manera genérica. No desea tener que implementar un método "ToXML" y "FromXML" para cada tipo que desea serializar, desea algunos medios genéricos para asegurarse de que su tipo haga esto y simplemente funcione. Quieres reutilizar el código.
Si su idioma lo admite, puede crear el mixin serializable Xml para que haga su trabajo por usted. Este tipo implementaría los métodos ToXML y FromXML. Con un mecanismo que no es importante para el ejemplo, sería capaz de recopilar todos los datos necesarios de cualquier tipo con el que se mezcle para construir el fragmento XML devuelto por ToXML y sería igualmente capaz de restaurar esos datos cuando FromXML sea llamado.
Y eso es. Para usarlo, debe tener cualquier tipo que necesite ser serializado a XML heredado de XmlSerializable. Siempre que necesite serializar o deserializar ese tipo, simplemente llame a ToXML o FromXML. De hecho, dado que XmlSerializable es un tipo completo y polimórfico, posiblemente podría construir un serializador de documentos que no sepa nada sobre su tipo original, aceptando solo, por ejemplo, una matriz de tipos XmlSerializable.
Ahora imagine usar este escenario para otras cosas, como crear un mixin que garantice que cada clase que lo mezcla en el registro registre todas las llamadas a métodos, o un mixin que proporcione transaccionalidad al tipo que lo mezcla. La lista puede seguir y seguir.
Si solo piensas en un mixin como un tipo base pequeño diseñado para agregar una pequeña cantidad de funcionalidad a un tipo sin afectar ese tipo, entonces eres dorado.
Ojalá. :)
fuente
Esta respuesta tiene como objetivo explicar los mixins con ejemplos que son:
autocontenido : breve, sin necesidad de conocer ninguna biblioteca para comprender el ejemplo.
en Python , no en otros idiomas.
Es comprensible que haya ejemplos de otros idiomas, como Ruby, ya que el término es mucho más común en esos idiomas, pero este es un hilo de Python .
También considerará la controvertida pregunta:
Definiciones
Todavía tengo que ver una cita de una fuente "autorizada" que diga claramente qué es un mixin en Python.
He visto 2 posibles definiciones de un mixin (si se consideran diferentes de otros conceptos similares, como las clases base abstractas), y las personas no están totalmente de acuerdo sobre cuál es la correcta.
El consenso puede variar entre diferentes idiomas.
Definición 1: sin herencia múltiple
Un mixin es una clase tal que algún método de la clase usa un método que no está definido en la clase.
Por lo tanto, la clase no debe ser instanciada, sino que sirve como una clase base. De lo contrario, la instancia tendría métodos que no se pueden invocar sin generar una excepción.
Una restricción que agregan algunas fuentes es que la clase puede no contener datos, solo métodos, pero no veo por qué esto es necesario. Sin embargo, en la práctica, muchos mixins útiles no tienen datos, y las clases base sin datos son más fáciles de usar.
Un ejemplo clásico es la implementación de todos los operadores de comparación de solo
<=
y==
:Este ejemplo en particular podría haberse logrado a través del
functools.total_ordering()
decorador, pero el juego aquí fue reinventar la rueda:Definición 2: herencia múltiple
Un mixin es un patrón de diseño en el que algún método de una clase base usa un método que no define, y ese método está destinado a ser implementado por otra clase base , no por el derivado como en la Definición 1.
El término clase mixin se refiere a las clases base que están destinadas a usarse en ese patrón de diseño (¿TODOS los que usan el método o los que lo implementan?)
No es fácil decidir si una clase dada es una combinación o no: el método podría implementarse solo en la clase derivada, en cuyo caso volvemos a la Definición 1. Debe considerar las intenciones del autor.
Este patrón es interesante porque es posible recombinar funcionalidades con diferentes opciones de clases base:
Ocurrencias autorizadas de Python
En la documentación oficial de collections.abc, la documentación utiliza explícitamente el término Métodos Mixin .
Establece que si una clase:
__next__
Iterator
entonces la clase obtiene un
__iter__
método mixin gratis.Por lo tanto, al menos en este punto de la documentación, mixin no requiere herencia múltiple , y es coherente con la Definición 1.
La documentación podría ser, por supuesto, contradictoria en diferentes puntos, y otras bibliotecas importantes de Python podrían estar utilizando la otra definición en su documentación.
Esta página también usa el término
Set mixin
, que sugiere claramente que a las clases les gustanSet
yIterator
pueden llamarse clases Mixin.En otros idiomas
Ruby: Claramente no requiere herencia múltiple para mixin, como se menciona en los principales libros de referencia como Programming Ruby y The Ruby programación Language
C ++: un método que no se implementa es un método virtual puro.
La definición 1 coincide con la definición de una clase abstracta (una clase que tiene un método virtual puro). Esa clase no puede ser instanciada.
La definición 2 es posible con herencia virtual: herencia múltiple de dos clases derivadas
fuente
Pienso en ellos como una forma disciplinada de usar la herencia múltiple, porque en última instancia, un mixin es solo otra clase de python que (podría) seguir las convenciones sobre las clases que se llaman mixins.
Mi comprensión de las convenciones que rigen algo que llamarías Mixin es que un Mixin:
object
(en Python)De esta forma, limita la complejidad potencial de la herencia múltiple y hace que sea razonablemente fácil rastrear el flujo de su programa al limitar dónde debe mirar (en comparación con la herencia múltiple completa). Son similares a los módulos ruby .
Si quiero agregar variables de instancia (con más flexibilidad que la permitida por una sola herencia), entonces tiendo a elegir la composición.
Dicho esto, he visto clases llamadas XYZMixin que tienen variables de instancia.
fuente
Mixins es un concepto en Programación en el que la clase proporciona funcionalidades pero no está destinado a ser utilizado para la creación de instancias. El propósito principal de Mixins es proporcionar funcionalidades que son independientes y sería mejor si las mixins en sí no tienen herencia con otras mixins y también evitan el estado. En lenguajes como Ruby, hay algún soporte directo de lenguaje, pero para Python, no lo hay. Sin embargo, podría usar la herencia de varias clases para ejecutar la funcionalidad proporcionada en Python.
Vi este video http://www.youtube.com/watch?v=v_uKI2NOLEM para comprender los conceptos básicos de los mixins. Es bastante útil para un principiante comprender los conceptos básicos de los mixins y cómo funcionan y los problemas que puede enfrentar al implementarlos.
Wikipedia sigue siendo la mejor: http://en.wikipedia.org/wiki/Mixin
fuente
Un mixin es una forma limitada de herencia múltiple. En algunos idiomas, el mecanismo para agregar un mixin a una clase es ligeramente diferente (en términos de sintaxis) del de herencia.
Especialmente en el contexto de Python, un mixin es una clase principal que proporciona funcionalidad a las subclases pero no está diseñada para ser instanciada por sí misma.
Lo que podría hacer que diga, "eso es solo herencia múltiple, no realmente un mixin" es si la clase que podría confundirse con un mixin realmente puede ser instanciada y utilizada, por lo que es una diferencia semántica y muy real.
Ejemplo de herencia múltiple
Este ejemplo, de la documentación , es un OrderedCounter:
Subclasifica tanto el
Counter
como elOrderedDict
decollections
módulo.Ambos
Counter
yOrderedDict
están destinados a ser instanciados y utilizados por sí mismos. Sin embargo, al subclasificarlos a ambos, podemos tener un contador ordenado y reutilizar el código en cada objeto.Esta es una forma poderosa de reutilizar el código, pero también puede ser problemático. Si resulta que hay un error en uno de los objetos, arreglarlo sin cuidado podría crear un error en la subclase.
Ejemplo de un mixin
Los mixins generalmente se promueven como la forma de reutilizar el código sin posibles problemas de acoplamiento que podría tener la herencia múltiple cooperativa, como el OrderedCounter. Cuando usa mixins, usa una funcionalidad que no está tan estrechamente unida a los datos.
A diferencia del ejemplo anterior, un mixin no está destinado a usarse solo. Proporciona funcionalidad nueva o diferente.
Por ejemplo, la biblioteca estándar tiene un par de mixins en la
socketserver
biblioteca .En este caso, los métodos mixin anulan los métodos en la
UDPServer
definición del objeto para permitir la concurrencia.El método reemplazado parece ser
process_request
y también proporciona otro método,process_request_thread
. Aquí es del código fuente :Un ejemplo contribuido
Este es un mixin principalmente para fines de demostración: la mayoría de los objetos evolucionarán más allá de la utilidad de esta repr:
y el uso sería:
Y uso:
fuente
Creo que ha habido algunas buenas explicaciones aquí, pero quería ofrecer otra perspectiva.
En Scala, puede hacer mixins como se ha descrito aquí, pero lo que es muy interesante es que los mixins en realidad se fusionan para crear un nuevo tipo de clase para heredar. En esencia, no heredas de múltiples clases / mixins, sino que generas un nuevo tipo de clase con todas las propiedades del mixin para heredar. Esto tiene sentido ya que Scala se basa en la JVM donde la herencia múltiple no es compatible actualmente (a partir de Java 8). Este tipo de clase mixin, por cierto, es un tipo especial llamado Rasgo en Scala.
Se insinúa en la forma en que se define una clase: la clase NewClass extiende FirstMixin con SecondMixin con ThirdMixin ...
No estoy seguro de si el intérprete de CPython hace lo mismo (mixin class-composition) pero no me sorprendería. Además, viniendo de un entorno C ++, no llamaría un ABC o 'interfaz' equivalente a un mixin: es un concepto similar pero divergente en uso e implementación.
fuente
Aconsejaría contra las mezclas en el nuevo código de Python, si puede encontrar otra forma de evitarlo (como composición en lugar de herencia, o simplemente métodos de parches de mono en sus propias clases), eso no es mucho más esfuerzo.
En las clases de estilo antiguo, podría usar mezclas como una forma de obtener algunos métodos de otra clase. Pero en el mundo del nuevo estilo, todo, incluso la mezcla, hereda
object
. Eso significa que cualquier uso de herencia múltiple naturalmente presenta problemas de MRO .Hay formas de hacer que MRO de herencia múltiple funcione en Python, especialmente la función super (), pero significa que tienes que hacer toda tu jerarquía de clases usando super (), y es considerablemente más difícil entender el flujo de control.
fuente
Quizás un par de ejemplos ayudarán.
Si está creando una clase y desea que actúe como un diccionario, puede definir todos los diversos
__ __
métodos necesarios. Pero eso es un poco doloroso. Como alternativa, puede definir algunas y heredar (además de cualquier otra herencia) deUserDict.DictMixin
(movido acollections.DictMixin
py3k). Esto tendrá el efecto de definir automáticamente todo el resto de la API del diccionario.Un segundo ejemplo: el kit de herramientas GUI wxPython le permite crear controles de lista con múltiples columnas (como, por ejemplo, la visualización del archivo en el Explorador de Windows). Por defecto, estas listas son bastante básicas. Puede agregar funcionalidad adicional, como la capacidad de ordenar la lista por una columna en particular haciendo clic en el encabezado de la columna, heredando de ListCtrl y agregando los mixins apropiados.
fuente
No es un ejemplo de Python, pero en el lenguaje de programación D el término
mixin
se usa para referirse a una construcción utilizada de la misma manera; agregando un montón de cosas a una clase.En D (que por cierto no hace MI), esto se hace insertando una plantilla (piense en macros sintácticamente conscientes y seguras y estará cerca) en un ámbito. Esto permite una sola línea de código en una clase, estructura, función, módulo o lo que sea para expandirse a cualquier número de declaraciones.
fuente
OP mencionó que él / ella nunca escuchó sobre mixin en C ++, tal vez porque se llaman Curiously Recurring Template Pattern (CRTP) en C ++. Además, @Ciro Santilli mencionó que mixin se implementa a través de la clase base abstracta en C ++. Si bien la clase base abstracta se puede usar para implementar mixin, es una exageración ya que la funcionalidad de la función virtual en tiempo de ejecución se puede lograr usando la plantilla en tiempo de compilación sin la sobrecarga de la búsqueda de tabla virtual en tiempo de ejecución.
El patrón CRTP se describe en detalle aquí
He convertido el ejemplo de Python en la respuesta de @Ciro Santilli a C ++ usando la clase de plantilla a continuación:
EDITAR: Se agregó un constructor protegido en ComparableMixin para que solo se pueda heredar y no instanciar. Se actualizó el ejemplo para mostrar cómo el constructor protegido causará un error de compilación cuando se crea un objeto de ComparableMixin.
fuente
Quizás un ejemplo de ruby pueda ayudar:
Puede incluir el mixin
Comparable
y definir una función"<=>(other)"
, el mixin proporciona todas esas funciones:Lo hace invocando
<=>(other)
y devolviendo el resultado correcto."instance <=> other"
devuelve 0 si ambos objetos son iguales, menor que 0 siinstance
es mayor queother
y mayor que 0 siother
es mayor.fuente
__lt__
como base en lugar de__cmp__
, la última de las cuales en realidad está en desuso y se desaconseja su uso. Para mí, parece más simple usar ese mixin en lugar de decoradores bastante complicados (parte de functools ), aunque este podría ser capaz de reaccionar más dinámicamente sobre las comparaciones que se proporcionan ...mixin brinda una forma de agregar funcionalidad en una clase, es decir, puede interactuar con los métodos definidos en un módulo al incluir el módulo dentro de la clase deseada. Aunque ruby no admite herencia múltiple, proporciona mixin como alternativa para lograrlo.
Aquí hay un ejemplo que explica cómo se logra la herencia múltiple usando mixin.
fuente
Acabo de usar un Python Mixin para implementar pruebas unitarias para Python Milters. Normalmente, un milter habla con una MTA, lo que dificulta las pruebas unitarias. La mezcla de prueba anula los métodos que se comunican con el MTA y, en su lugar, crean un entorno simulado impulsado por casos de prueba.
Entonces, tomas una aplicación de milter no modificada, como spfmilter, y mixin TestBase, así:
Luego, use TestMilter en los casos de prueba para la aplicación milter:
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
fuente
Creo que las respuestas anteriores definieron muy bien lo que son los MixIns . Sin embargo, para comprenderlos mejor, podría ser útil comparar MixIns con clases e interfaces abstractas desde la perspectiva del código / implementación:
1. Clase abstracta
Clase que necesita contener uno o más métodos abstractos
La clase abstracta puede contener estados (variables de instancia) y métodos no abstractos
2. interfaz
3. MixIns
En, por ejemplo, Python, estas son solo convenciones, porque todo lo anterior se define como
class
es. Sin embargo, la característica común de ambas clases abstractas, interfaces y MixIns es que no deberían existir por sí mismas, es decir, no deberían ser instanciadas.fuente
Leí que tienes un fondo ac #. Entonces, un buen punto de partida podría ser una implementación mixin para .NET.
Es posible que desee consultar el proyecto codeplex en http://remix.codeplex.com/
Mire el enlace del simposio lang.net para obtener una descripción general. Todavía hay más por venir en la documentación en la página de codeplex.
saludos Stefan
fuente