python - multiple - ¿Qué es una mezcla y por qué son útiles?
multiple inheritance python (15)
En " Programming Python ", Mark Lutz menciona "mixins". Soy de un fondo de C / C ++ / C # y no he escuchado el término antes. ¿Qué es una mezcla?
Leyendo entre líneas en este ejemplo (al que he vinculado porque es bastante largo), supongo que es un caso de uso de herencia múltiple para extender una clase en lugar de subclasificación "adecuada". ¿Es esto correcto?
¿Por qué querría hacer eso en lugar de poner la nueva funcionalidad en una subclase? En este sentido, ¿por qué sería mejor un enfoque mixto / herencia múltiple que el uso de la composición?
¿Qué separa una mezcla de la herencia múltiple? ¿Es sólo una cuestión de semántica?
¿Qué separa una mezcla de la herencia múltiple? ¿Es sólo una cuestión de semántica?
Una mezcla es una forma limitada de herencia múltiple. En algunos idiomas, el mecanismo para agregar una mezcla a una clase es ligeramente diferente (en términos de sintaxis) del de herencia.
Especialmente en el contexto de Python, una mezcla es una clase principal que proporciona funcionalidad a las subclases, pero no está diseñada para ser instanciada.
Lo que podría hacer que usted diga, "eso es solo herencia múltiple, no es realmente una mezcla" es si la clase que podría confundirse con una mezcla puede realmente 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:
class OrderedCounter(Counter, OrderedDict): ''Counter that remembers the order elements are first encountered'' def __repr__(self): return ''%s(%r)'' % (self.__class__.__name__, OrderedDict(self)) def __reduce__(self): return self.__class__, (OrderedDict(self),)
OrderedDict
tanto el Counter
como el OrderedDict
del módulo de collections
.
Tanto Counter
como OrderedDict
están diseñados para ser instanciados y utilizados por sí mismos. Sin embargo, al subclasificarlos a ambos, podemos tener un contador que está ordenado y reutiliza 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, corregirlo sin cuidado podría crear un error en la subclase.
Ejemplo de un Mixin
Los mixins generalmente se promocionan como la forma de obtener la reutilización del código sin problemas de acoplamiento potenciales que podría tener la herencia múltiple cooperativa, como el OrderedCounter. Cuando utiliza mixins, utiliza una funcionalidad que no está tan estrechamente unida a los datos.
A diferencia del ejemplo anterior, un mixin no está diseñado para usarse solo. Proporciona funcionalidad nueva o diferente.
Por ejemplo, la biblioteca estándar tiene un par de mixins en la biblioteca de socketserver
.
Las versiones de bifurcación y subprocesamiento de cada tipo de servidor se pueden crear utilizando estas clases de mezcla. Por ejemplo, ThreadingUDPServer se crea de la siguiente manera:
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
La clase de mezcla viene primero, ya que anula un método definido en UDPServer. La configuración de los diversos atributos también cambia el comportamiento del mecanismo del servidor subyacente.
En este caso, los métodos de UDPServer
anulan los métodos en la definición de objeto UDPServer
para permitir la concurrencia.
El método anulado parece ser process_request
y también proporciona otro método, process_request_thread
. Aquí está del código fuente :
class ThreadingMixIn: """Mix-in class to handle each request in a new thread.""" # Decides how threads will act upon termination of the # main process daemon_threads = False def process_request_thread(self, request, client_address): """Same as in BaseServer but as a thread. In addition, exception handling is done here. """ try: self.finish_request(request, client_address) except Exception: self.handle_error(request, client_address) finally: self.shutdown_request(request) def process_request(self, request, client_address): """Start a new thread to process the request.""" t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads t.start()
Un ejemplo elaborado
Esta es una mezcla que es principalmente para fines de demostración: la mayoría de los objetos evolucionarán más allá de la utilidad de esta reproducción:
class SimpleInitReprMixin(object):
"""mixin, don''t instantiate - useful for classes instantiable
by keyword arguments to their __init__ method.
"""
__slots__ = () # allow subclasses to use __slots__ to prevent __dict__
def __repr__(self):
kwarg_strings = []
d = getattr(self, ''__dict__'', None)
if d is not None:
for k, v in d.items():
kwarg_strings.append(''{k}={v}''.format(k=k, v=repr(v)))
slots = getattr(self, ''__slots__'', None)
if slots is not None:
for k in slots:
v = getattr(self, k, None)
kwarg_strings.append(''{k}={v}''.format(k=k, v=repr(v)))
return ''{name}({kwargs})''.format(
name=type(self).__name__,
kwargs='', ''.join(kwarg_strings)
)
y el uso sería:
class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
__slots__ = ''foo'',
def __init__(self, foo=None):
self.foo = foo
super(Foo, self).__init__()
Y uso:
>>> f1 = Foo(''bar'')
>>> f2 = Foo()
>>> f1
Foo(foo=''bar'')
>>> f2
Foo(foo=None)
Acabo de usar un mixin de python para implementar pruebas unitarias para milters de python. Normalmente, un milter habla con un MTA, lo que dificulta las pruebas de unidad. La mezcla de prueba anula los métodos que hablan con el MTA y, en su lugar, crea un entorno simulado controlado por casos de prueba.
Entonces, tomas una aplicación de milter sin modificar, como spfmilter, y mezcla en TestBase, como esto:
class TestMilter(TestBase,spfmilter.spfMilter):
def __init__(self):
TestBase.__init__(self)
spfmilter.config = spfmilter.Config()
spfmilter.config.access_file = ''test/access.db''
spfmilter.spfMilter.__init__(self)
Luego, use TestMilter en los casos de prueba para la aplicación milter:
def testPass(self):
milter = TestMilter()
rc = milter.connect(''mail.example.com'',ip=''192.0.2.1'')
self.assertEqual(rc,Milter.CONTINUE)
rc = milter.feedMsg(''test1'',sender=''[email protected]'')
self.assertEqual(rc,Milter.CONTINUE)
milter.close()
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
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 están "fusionados" para crear un nuevo tipo de clase para heredar. En esencia, no hereda de varias clases / mixins, sino que genera un nuevo tipo de clase con todas las propiedades de la mezcla para heredar. Esto tiene sentido ya que Scala se basa en la JVM donde actualmente no se admite la herencia múltiple (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 (mezclando composición de clase) pero no me sorprendería. Además, proveniente de un fondo de C ++, no llamaría un ABC o "interfaz" equivalente a una mezcla, es un concepto similar pero divergente en uso e implementación.
Esta respuesta apunta a 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 se considerará la cuestión controvertida:
¿Es necesaria la herencia múltiple o no para caracterizar una mezcla?
Definiciones
Todavía tengo que ver una cita de una fuente "autorizada" que dice claramente qué es una mezcla en Python.
He visto 2 definiciones posibles de un mixin (si han de considerarse como diferentes de otros conceptos similares, como las clases básicas abstractas), y las personas no están del todo de acuerdo en cuál es la correcta.
El consenso puede variar entre diferentes idiomas.
Definición 1: sin herencia múltiple
Una mezcla 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 está destinada a ser instanciada, sino que sirve como una clase base. De lo contrario, la instancia tendría métodos a los que no se puede llamar sin generar una excepción.
Una restricción que algunas fuentes agregan 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 desde solo <=
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
Este ejemplo en particular podría haberse logrado a través del decorador functools.total_ordering()
, pero el juego aquí fue reinventar la rueda:
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)
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 de mezcla se refiere a las clases base que están destinadas a usarse en ese patrón de diseño (¿TODO aquellos que usan el método o aquellos que lo implementan?)
No es fácil decidir si una clase dada es una combinación o no: el método podría implementarse en la clase derivada, en cuyo caso volvemos a la Definición 1. Debe tener en cuenta las intenciones del autor.
Este patrón es interesante porque es posible recombinar funcionalidades con diferentes opciones de clases básicas:
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
Apariciones de Python autorizadas
En la documentación oficial para colecciones.abc, la documentación utiliza explícitamente el término Métodos de mezcla .
Afirma que si una clase:
- implementa
__next__
- hereda de una sola clase
Iterator
entonces la clase obtiene un método de __iter__
gratis.
Por lo tanto, al menos en este punto de la documentación, la mezcla no requiere herencia múltiple , y es coherente con la Definición 1.
La documentación podría, por supuesto, ser contradictoria en diferentes puntos, y otras bibliotecas importantes de Python podrían estar usando la otra definición en su documentación.
Esta página también usa el término Set mixin
, que sugiere claramente que las clases como Set
e Iterator
se pueden llamar clases Mixin.
En otros idiomas
Ruby: Claramente no requiere herencia múltiple para la mezcla, como se menciona en los principales libros de referencia como Programación de Ruby y el lenguaje de programación The Ruby
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
Leí que tienes un fondo de AC #. Por lo tanto, un buen punto de partida podría ser una implementación mixta para .NET.
Es posible que desee revisar el proyecto codeplex en http://remix.codeplex.com/
Mire el enlace del simposio de 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 a Stefan
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 sean independientes y sería mejor si las Mixins en sí mismas no tienen herencia con otras Mixins y también evitan el estado. En lenguajes como Ruby, hay un soporte de lenguaje directo, pero para Python, no lo hay. Sin embargo, podría utilizar 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 muy útil para un principiante entender los conceptos básicos de los mixins y cómo funcionan y los problemas que podría enfrentar al implementarlos.
Wikipedia sigue siendo el mejor: http://en.wikipedia.org/wiki/Mixin
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 que se usa de la misma forma; añadiendo 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 seguras y sintácticamente conscientes 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 expandir a cualquier número de declaraciones.
OP mencionó que él / ella nunca escuchó acerca de la mezcla en C ++, tal vez es porque se les llama Curiously Recurring Template Pattern (CRTP) en C ++. Además, @Ciro Santilli mencionó que la mezcla se implementa a través de la clase base abstracta en C ++. Si bien la clase base abstracta se puede usar para implementar la mezcla, es una exageración, ya que la funcionalidad de la función virtual en tiempo de ejecución puede lograrse utilizando una plantilla en tiempo de compilación sin la sobrecarga de la búsqueda de tablas virtuales en tiempo de ejecución.
El patrón CRTP se describe en detalle here
He convertido el ejemplo de python en la respuesta de @Ciro Santilli en C ++ usando la clase de plantilla a continuación:
#include <iostream>
#include <assert.h>
template <class T>
class ComparableMixin {
public:
bool operator !=(ComparableMixin &other) {
return ~(*static_cast<T*>(this) == static_cast<T&>(other));
}
bool operator <(ComparableMixin &other) {
return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
}
bool operator >(ComparableMixin &other) {
return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
}
bool operator >=(ComparableMixin &other) {
return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
}
};
class Integer: public ComparableMixin<Integer> {
public:
Integer(int i) {
this->i = i;
}
int i;
bool operator <=(Integer &other) {
return (this->i <= other.i);
}
bool operator ==(Integer &other) {
return (this->i == other.i);
}
};
int main() {
Integer i(0) ;
Integer j(1) ;
assert (i < j );
assert (i != j);
assert (j > i);
assert (j >= i);
return 0;
}
Pienso en ellos como una forma disciplinada de usar la herencia múltiple, porque en última instancia, una mezcla es solo otra clase de python que (podría) seguir las convenciones sobre las clases que se denominan mezclas.
Mi comprensión de las convenciones que gobiernan algo que podríamos llamar un Mixin es que un Mixin:
- agrega métodos pero no variables de instancia (las constantes de clase son correctas)
- solo hereda de
object
(en Python)
De esa manera, 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 de rubí.
Si quiero agregar variables de instancia (con más flexibilidad de la que permite una herencia única), tiendo a ir a la composición.
Dicho esto, he visto clases llamadas XYZMixin que sí tienen variables de instancia.
Primero, debe tener en cuenta que los mixins solo existen en idiomas de herencia múltiple. No puedes hacer una mezcla en Java o C #.
Básicamente, una mezcla 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 tenga que implementar realmente porque ya está implementada; simplemente hereda de él y se beneficia de su funcionalidad.
Los mixins son típicamente estrechos en su alcance y no están destinados a ser extendidos.
[editar - por qué:]
Supongo que debería abordar el porqué, ya que lo pediste. El gran beneficio es que no tienes que hacerlo tú mismo una y otra vez. En C #, el lugar más grande donde una mezcla podría beneficiarse podría ser el patrón de Disposición . Cada vez que implementas IDisposable, casi siempre quieres seguir el mismo patrón, pero terminas escribiendo y reescribiendo el mismo código básico con pequeñas variaciones. Si hubiera una mezcla de eliminación extensible, podría ahorrarse muchos tipos adicionales de escritura.
[edit 2 - para responder a tus otras preguntas]
¿Qué separa una mezcla de la herencia múltiple? ¿Es sólo una cuestión de semántica?
Sí. La diferencia entre una mezcla y una herencia múltiple estándar es solo una cuestión de semántica; una clase que tiene herencia múltiple puede utilizar un mixin como parte de esa herencia múltiple.
El objetivo de una mezcla es crear un tipo que se pueda "mezclar" con cualquier otro tipo a través de la herencia sin afectar al tipo hereditario y al mismo tiempo ofrecer alguna funcionalidad beneficiosa para ese tipo.
Nuevamente, piense en una interfaz que ya está implementada.
Personalmente no uso los mixins, ya que me desarrollo principalmente en un lenguaje que no los admite, por lo que me está costando mucho dar un ejemplo decente que simplemente proporcione ese "¡ahah!" momento para ti Pero lo intentaré de nuevo. Voy a usar un ejemplo que está diseñado (la mayoría de los idiomas ya proporcionan la característica de una forma u otra), pero eso, con suerte, explicará cómo se supone que se crean y usan los 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 devuelva una cadena que contenga un fragmento XML con los valores de datos del tipo, y un "FromXML" que permita al tipo reconstruir sus valores de datos de un fragmento XML en una cadena. Nuevamente, 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 una manera genérica. No desea tener que implementar un método "ToXML" y "FromXML" para cada tipo que desee serializar, quiere algunos medios genéricos para asegurarse de que su tipo hará esto y simplemente funciona. Quieres reutilizar el código.
Si su idioma lo admite, puede crear la mezcla XmlSerializable para hacer su trabajo por usted. Este tipo implementaría los métodos ToXML y FromXML. Utilizando algún mecanismo que no sea 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 es llamado.
Y eso es. Para usarlo, debe tener cualquier tipo que deba ser serializado a XML heredado de XmlSerializable. Cuando necesitara serializar o deserializar ese tipo, simplemente llamaría a ToXML o FromXML. De hecho, dado que XmlSerializable es un tipo completo y polimórfico, posiblemente podría crear un serializador de documentos que no sepa nada sobre su tipo original, aceptando solo, por ejemplo, una variedad de tipos XmlSerializable.
Ahora imagine utilizar este escenario para otras cosas, como crear una mezcla que garantice que cada clase que la mezcle registre cada llamada de método o una combinación que ofrezca transaccionalidad al tipo que la mezcla. La lista puede seguir y seguir.
Si solo piensas en una mezcla como un tipo de base pequeña diseñada para agregar una pequeña cantidad de funcionalidad a un tipo sin afectar ese tipo, entonces estás de oro.
Ojalá. :)
Quizás un par de ejemplos ayuden.
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 de dolor. Como alternativa, solo puede definir algunos y heredar (además de cualquier otra herencia) de UserDict.DictMixin
(trasladado a collections.DictMixin
en 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 realizar controles de lista con varias 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.
Recomiendo que no se mezclen con el nuevo código de Python, si puedes encontrar alguna otra forma de evitarlo (como la composición en lugar de la herencia, o simplemente los métodos de parches de mono en tus propias clases) eso no es mucho más. esfuerzo.
En las clases de estilo antiguo, puedes usar combinaciones para agarrar algunos métodos de otra clase. Pero en el mundo del nuevo estilo todo, incluso la mezcla, hereda del object
. Eso significa que cualquier uso de herencia múltiple naturalmente introduce problemas de MRO .
Hay formas de hacer que el MRO de herencia múltiple funcione en Python, especialmente la función super (), pero significa que debe hacer toda la jerarquía de clases usando super (), y es mucho más difícil entender el flujo de control.
Tal vez un ejemplo de ruby puede ayudar:
Puede incluir el Mixin Comparable
y definir una función "<=>(other)"
, el mixin proporciona todas esas funciones:
<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)
Hace esto invocando <=>(other)
y devolviendo el resultado correcto.
"instance <=> other"
devuelve 0 si ambos objetos son iguales, menos que 0 si la instance
es más grande que other
y más que 0 si other
es más grande.
Un mixin es un tipo especial de herencia múltiple. Hay dos situaciones principales en las que se utilizan mixins:
- Desea proporcionar muchas características opcionales para una clase.
- Desea utilizar una característica particular en muchas clases diferentes.
Para un ejemplo del número uno, considere el sistema de solicitud y respuesta de werkzeug . Puedo hacer un objeto de solicitud antiguo simple diciendo:
from werkzeug import BaseRequest
class Request(BaseRequest):
pass
Si quisiera agregar aceptar el soporte de encabezado, haría que
from werkzeug import BaseRequest, AcceptMixin
class Request(AcceptMixin, BaseRequest):
pass
Si quisiera hacer un objeto de solicitud que admita encabezados, etags, autenticación y soporte de agente de usuario, podría hacer esto:
from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin
class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
pass
La diferencia es sutil, pero en los ejemplos anteriores, las clases mixtas no se hicieron por sí solas. En la herencia múltiple más tradicional, la AuthenticationMixin
(por ejemplo) probablemente sería algo más como Authenticator
. Es decir, la clase probablemente estaría diseñada para valerse por sí misma.
mixin ofrece 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, pero proporciona mixin como una alternativa para lograrlo.
Aquí hay un ejemplo que explica cómo se logra la herencia múltiple utilizando 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