Что такое миксин и почему они полезны?
В " Программировании Python" Марк Лутц упоминает "миксины". Я из C/C++/C# фона, и я не слышал этот термин раньше. Что такое миксин?
Читая между строк этого примера (который я связал, потому что он довольно длинный), я предполагаю, что это случай использования множественного наследования для расширения класса, а не для "правильного" подкласса. Это правильно?
Почему я хотел бы сделать это, а не помещать новую функциональность в подкласс? В этом отношении, почему подход смешанного / множественного наследования лучше, чем использование композиции?
Что отличает миксин от множественного наследования? Это просто вопрос семантики?
18 ответов
Миксин - это особый вид множественного наследования. Есть две основные ситуации, в которых используются миксины:
- Вы хотите предоставить много дополнительных функций для класса.
- Вы хотите использовать одну особенность во множестве разных классов.
Для примера номер один рассмотрим систему запросов и ответов werkzeug. Я могу сделать простой старый объект запроса, сказав:
from werkzeug import BaseRequest
class Request(BaseRequest):
pass
Если я хочу добавить поддержку заголовка принять, я бы сделал это
from werkzeug import BaseRequest, AcceptMixin
class Request(AcceptMixin, BaseRequest):
pass
Если бы я хотел создать объект запроса, который поддерживает заголовки принятия, etags, аутентификацию и поддержку агента пользователя, я мог бы сделать это:
from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin
class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
pass
Разница невелика, но в приведенных выше примерах классы mixin не создавались самостоятельно. В более традиционном множественном наследовании AuthenticationMixin
(например), вероятно, будет что-то вроде Authenticator
, Таким образом, класс, вероятно, был бы разработан, чтобы стоять самостоятельно.
Во-первых, вы должны заметить, что миксины существуют только в языках множественного наследования. Вы не можете сделать миксин в Java или C#.
По сути, миксин - это автономный базовый тип, который обеспечивает ограниченную функциональность и полиморфный резонанс для дочернего класса. Если вы думаете о C#, подумайте об интерфейсе, который вам не нужно реализовывать, потому что он уже реализован; вы просто наследуете его и извлекаете выгоду из его функциональности.
Миксины обычно узкие по объему и не предназначены для расширения.
[править - почему:]
Полагаю, мне следует ответить на вопрос, почему, поскольку вы спросили. Большим преимуществом является то, что вам не нужно делать это снова и снова. В C# самое большое место, где миксин может извлечь выгоду, может быть из шаблона утилизации. Всякий раз, когда вы реализуете IDisposable, вы почти всегда хотите следовать одному и тому же шаблону, но в итоге вы пишете и переписываете один и тот же базовый код с небольшими изменениями. Если бы существовал расширяемый миксин Disposal, вы могли бы сэкономить много лишнего набора текста.
[править 2 - чтобы ответить на другие ваши вопросы]
Что отличает миксин от множественного наследования? Это просто вопрос семантики?
Да. Разница между миксином и стандартным множественным наследованием является лишь вопросом семантики; класс с множественным наследованием может использовать миксин как часть этого множественного наследования.
Смысл mixin состоит в том, чтобы создать тип, который можно "примешать" к любому другому типу посредством наследования, не затрагивая наследующий тип, и в то же время предлагать некоторые полезные функции для этого типа.
Опять же, подумайте об интерфейсе, который уже реализован.
Лично я не использую миксины, так как я развиваюсь в основном на языке, который их не поддерживает, поэтому мне очень трудно придумать достойный пример, который просто поставит это "ахах!" момент для вас. Но я попробую еще раз. Я собираюсь использовать надуманный пример - большинство языков уже так или иначе предоставляют эту возможность - но, надеюсь, это объяснит, как миксины должны создаваться и использоваться. Вот оно:
Предположим, у вас есть тип, который вы хотите иметь возможность сериализации в и из XML. Вы хотите, чтобы тип предоставил метод "ToXML", который возвращает строку, содержащую фрагмент XML со значениями данных типа, и "FromXML", который позволяет типу восстанавливать свои значения данных из фрагмента XML в строку. Опять же, это надуманный пример, поэтому, возможно, вы используете файловый поток или класс XML Writer из библиотеки времени выполнения вашего языка... что угодно. Дело в том, что вы хотите сериализовать свой объект в XML и получить новый объект обратно из XML.
Другим важным моментом в этом примере является то, что вы хотите сделать это в общем виде. Вам не нужно реализовывать методы "ToXML" и "FromXML" для каждого типа, который вы хотите сериализовать, вам нужны некоторые общие средства, гарантирующие, что ваш тип будет делать это, и он просто работает. Вы хотите повторного использования кода.
Если ваш язык поддерживает это, вы можете создать миксин XmlSerializable, который сделает вашу работу за вас. Этот тип будет реализовывать методы ToXML и FromXML. При использовании некоторого механизма, который не важен для примера, он мог бы собрать все необходимые данные из любого типа, с которым он смешан, для создания фрагмента XML, возвращаемого ToXML, и он был бы в равной степени способен восстанавливать эти данные, когда FromXML называется.
И это все. Чтобы использовать его, вы должны иметь любой тип, который нужно сериализовать, чтобы XML наследовал от XmlSerializable. Всякий раз, когда вам нужно было сериализовать или десериализовать этот тип, вы просто вызываете ToXML или FromXML. Фактически, поскольку XmlSerializable является полноценным и полиморфным типом, вы можете создать сериализатор документов, который ничего не знает о вашем исходном типе, принимая только, скажем, массив типов XmlSerializable.
Теперь представьте, что вы можете использовать этот сценарий для других целей, например, для создания миксина, который гарантирует, что каждый класс, который смешивает его, регистрирует каждый вызов метода, или миксина, который обеспечивает транзакционность для типа, который его смешивает. Список можно продолжать и продолжать.
Если вы просто думаете о миксине как о небольшом базовом типе, предназначенном для добавления небольшого количества функциональности к типу, без какого-либо влияния на этот тип, то вы - золотой.
С надеждой.:)
Цель этого ответа - объяснить миксины на примерах:
автономный: короткий, без необходимости знать какие-либо библиотеки, чтобы понять пример.
в Python, а не в других языках.
Понятно, что были примеры из других языков, таких как Ruby, поскольку этот термин гораздо чаще встречается в этих языках, но это тема Python.
Он также должен рассмотреть спорный вопрос:
Многократное наследование необходимо или нет, чтобы характеризовать миксин?
Определения
Я до сих пор не видел цитату из "авторитетного" источника, в которой четко сказано, что такое миксин в Python.
Я видел 2 возможных определения миксина (если их следует считать отличными от других похожих концепций, таких как абстрактные базовые классы), и люди не совсем согласны с тем, какое из них является правильным.
Консенсус может отличаться для разных языков.
Определение 1: нет множественного наследования
Mixin - это такой класс, что некоторый метод класса использует метод, который не определен в классе.
Поэтому класс не предназначен для создания экземпляра, а служит базовым классом. В противном случае экземпляр будет иметь методы, которые нельзя вызвать без вызова исключения.
Ограничение, которое добавляют некоторые источники, состоит в том, что класс может не содержать данных, только методы, но я не понимаю, почему это необходимо. Однако на практике многие полезные миксины не имеют никаких данных, и базовые классы без данных проще в использовании.
Классическим примером является реализация всех операторов сравнения только <=
а также ==
:
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
Этот конкретный пример мог быть достигнут через functools.total_ordering()
Декоратор, но игра здесь была изобретать велосипед:
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)
Определение 2: множественное наследование
Миксин - это шаблон проектирования, в котором некоторый метод базового класса использует метод, который он не определяет, и этот метод предназначен для реализации другим базовым классом, а не производным, как в определении 1.
Термин класс mixin относится к базовым классам, которые предназначены для использования в этом шаблоне проектирования (TODO, которые используют метод, или те, которые его реализуют?)
Нелегко определить, является ли данный класс миксином или нет: метод может быть просто реализован в производном классе, и в этом случае мы вернемся к определению 1. Вы должны учитывать намерения автора.
Этот шаблон интересен тем, что можно комбинировать функции с различными вариантами выбора базовых классов:
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
Авторитетные появления Python
В официальной документации для collection.abc в документации явно используется термин Mixin Methods.
В нем говорится, что если класс:
- инвентарь
__next__
- наследуется от одного класса
Iterator
тогда класс получает __iter__
миксин метод бесплатно.
Поэтому, по крайней мере, в этом пункте документации, mixin не требует множественного наследования и согласуется с определением 1.
Разумеется, документация может быть противоречивой в разные моменты, и другие важные библиотеки Python могут использовать другое определение в своей документации.
Эта страница также использует термин Set mixin
, который ясно предполагает, что классы любят Set
а также Iterator
можно назвать классами Mixin.
На других языках
Ruby: Очевидно, не требуется множественное наследование для mixin, как упоминалось в основных справочниках, таких как Programming Ruby и The Ruby Language Language.
C++: метод, который не реализован, является чисто виртуальным методом.
Определение 1 совпадает с определением абстрактного класса (класса, который имеет чисто виртуальный метод). Этот класс не может быть создан.
Определение 2 возможно с виртуальным наследованием: множественное наследование от двух производных классов
Я думаю о них как о дисциплинированном способе использования множественного наследования - потому что в конечном итоге миксин - это просто еще один класс Python, который (может) следовать соглашениям о классах, которые называются миксинами.
Мое понимание соглашений, которые управляют чем-то, что вы бы назвали миксином, таково, что миксин:
- добавляет методы, но не переменные экземпляра (константы класса в порядке)
- наследуется только от
object
(в Python)
Таким образом, он ограничивает потенциальную сложность множественного наследования и позволяет достаточно легко отслеживать поток вашей программы, ограничивая область поиска (по сравнению с полным множественным наследованием). Они похожи на модули ruby.
Если я хочу добавить переменные экземпляра (с большей гибкостью, чем допускается одиночным наследованием), я склоняюсь к компоновке.
Сказав это, я видел классы с именем XYZMixin, которые имеют переменные экземпляра.
Я думаю, что предыдущие ответы очень хорошо определили, что такое MixIns. Однако, чтобы лучше понять их, может быть полезно сравнить MixIns с абстрактными классами и интерфейсами с точки зрения кода / реализации:
1. Абстрактный класс
Класс, который должен содержать один или несколько абстрактных методов
Абстрактный класс может содержать состояние (переменные экземпляра) и неабстрактные методы
2. Интерфейс
- Интерфейс содержит только абстрактные методы (не абстрактные методы и внутреннее состояние)
3. MixIns
- MixIns (как и интерфейсы) не содержат внутреннего состояния (переменных экземпляра)
- MixIns содержат один или несколько не абстрактных методов (они могут содержать не абстрактные методы, в отличие от интерфейсов)
Например, в Python это просто соглашения, потому что все вышеперечисленное определяется как class
es. Однако общая черта абстрактных классов, интерфейсов и MixIns заключается в том, что они не должны существовать сами по себе, т.е. не должны быть созданы.
Что отличает миксин от множественного наследования? Это просто вопрос семантики?
Mixin - это ограниченная форма множественного наследования. В некоторых языках механизм добавления миксина в класс немного отличается (с точки зрения синтаксиса) от механизма наследования.
В частности, в контексте Python, mixin - это родительский класс, который предоставляет функциональность подклассам, но не предназначен для самореализации.
Что может заставить вас сказать, что "это просто множественное наследование, а не миксин", так это то, что класс, который может быть сбит с толку за миксин, действительно может быть создан и использован - так что это действительно семантическая и очень реальная разница.
Пример множественного наследования
Этот пример из документации является 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),)
Это подклассы как Counter
и OrderedDict
от collections
модуль.
И то и другое Counter
а также OrderedDict
предназначены для реализации и использования самостоятельно. Однако, подклассифицируя их обоих, мы можем получить счетчик, который упорядочен и повторно использует код в каждом объекте.
Это мощный способ повторного использования кода, но он также может быть проблематичным. Если окажется, что в одном из объектов есть ошибка, ее исправление может привести к ошибке в подклассе.
Пример миксина
Миксины обычно рекламируются как способ повторного использования кода без потенциальных проблем связывания, которые могут возникнуть при совместном множественном наследовании, как, например, OrderedCounter. Когда вы используете миксины, вы используете функциональность, которая не так тесно связана с данными.
В отличие от приведенного выше примера, миксин не предназначен для самостоятельного использования. Это обеспечивает новую или другую функциональность.
Например, в стандартной библиотеке есть пара миксинов в socketserver
библиотека
Версии Forking и Threading для каждого типа сервера могут быть созданы с помощью этих смешанных классов. Например, ThreadingUDPServer создается следующим образом:
class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass
Первым является смешанный класс, поскольку он переопределяет метод, определенный в UDPServer. Установка различных атрибутов также изменяет поведение базового серверного механизма.
В этом случае методы mixin переопределяют методы в UDPServer
определение объекта для обеспечения параллелизма.
Переопределенный метод выглядит так: process_request
и это также обеспечивает другой метод, process_request_thread
, Вот это из исходного кода:
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()
Придуманный пример
Это миксин, который в основном предназначен для демонстрации - большинство объектов будут развиваться за пределами полезности этого отчета:
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)
)
и использование будет:
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__()
И использование:
>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)
Mixins - это концепция в программировании, в которой класс предоставляет функциональные возможности, но он не предназначен для использования в экземплярах. Основная цель Mixins состоит в том, чтобы предоставить функциональные возможности, которые являются автономными, и было бы лучше, если бы сами миксины не наследовали другие миксины и также избегали состояния. В таких языках, как Ruby, есть прямая языковая поддержка, но для Python нет. Однако вы можете использовать наследование нескольких классов для выполнения функций, предоставляемых в Python.
Я посмотрел это видео http://www.youtube.com/watch?v=v_uKI2NOLEM чтобы понять основы миксинов. Для новичка очень полезно понять основы миксинов и то, как они работают, и проблемы, с которыми вы можете столкнуться при их реализации.
Википедия по-прежнему лучшая: http://en.wikipedia.org/wiki/Mixin
Эта концепция исходит из магазина мороженого Steve's Ice Cream , основанного СтивомХерреллом в Сомервилле, штат Массачусетс, в 1973 году, где добавки (конфеты, пирожные и т. д.) смешивались с основными вкусами мороженого (ваниль, шоколад, так далее.).
Вдохновленные мороженым Стива, разработчики объектной системы Lisp Flavors впервые включили эту концепцию в язык программирования с небольшими вспомогательными классами, разработанными для улучшения других классов, известных как микс-ины, и большими автономными классами, известными как ароматы .
Таким образом, основная идея заключается в том, что микс-ин является многоразовым расширением («многоразовое» в отличие от «исключительного»; «расширение» в отличие от «базового»).
Обратите внимание, что это определение ортогонально понятиям одиночного или множественного наследования, а также понятиям абстрактного или конкретного класса. Смешанные классы могут использоваться для одиночного или множественного наследования, а смешанные классы имеют неполные интерфейсы, в то время как абстрактные классы имеют неполные реализации, а конкретные классы имеют полные реализации.
Имена смешанных классов обычно имеют суффикс «-MixIn», «-able» или «-ible», чтобы подчеркнуть их природу, как в стандартной библиотеке Python с
ThreadingMixIn
а также
ForkingMixIn
классыsocketserver
модуль, и
Hashable
,
Iterable
,
Callable
,
Awaitable
,
AsyncIterable
, а также
Reversible
классыcollections.abc
модуль.
Пример подмешанного класса, расширяющего встроенный Python
list
а также
dict
классы с возможностью ведения журнала:
import logging
class LoggingMixIn:
def __setitem__(self, key, value):
logging.info('Setting %r to %r', key, value)
super().__setitem__(key, value)
def __delitem__(self, key):
logging.info('Deleting %r', key)
super().__delitem__(key)
class LoggingList(LoggingMixIn, list):
pass
class LoggingDict(LoggingMixIn, dict):
pass
>>> logging.basicConfig(level=logging.INFO)
>>> l = LoggingList([False])
>>> d = LoggingDict({'a': False})
>>> l[0] = True
INFO:root:Setting 0 to True
>>> d['a'] = True
INFO:root:Setting 'a' to True
>>> del l[0]
INFO:root:Deleting 0
>>> del d['a']
INFO:root:Deleting 'a'
Я думаю, что здесь было несколько хороших объяснений, но я хотел представить другую точку зрения.
В Scala вы можете создавать миксины, как описано здесь, но что очень интересно, это то, что миксины фактически "слиты" вместе, чтобы создать новый тип класса для наследования. По сути, вы не наследуете от нескольких классов / миксинов, а генерируете новый тип классов со всеми свойствами миксина для наследования. Это имеет смысл, так как Scala основан на JVM, где множественное наследование в настоящее время не поддерживается (начиная с Java 8). Этот тип класса mixin, кстати, является специальным типом, называемым Trait в Scala.
На это намекает способ определения класса: класс NewClass расширяет FirstMixin с помощью SecondMixin с помощью ThirdMixin ...
Я не уверен, что интерпретатор CPython делает то же самое (миксин-класс-композиция), но я не удивлюсь. Кроме того, исходя из фона C++, я бы не назвал ABC или "интерфейс" эквивалентом mixin - это похожая концепция, но расходящаяся в использовании и реализации.
Я бы посоветовал не смешивать модули в новом коде Python, если вы можете найти какой-либо другой способ обойти это (например, метод "составление вместо наследования" или просто методы "залатывания обезьянами" в ваших собственных классах), который не намного больше усилия.
В классах старого стиля вы можете использовать встраиваемые модули как способ получить несколько методов из другого класса. Но в мире нового стиля все, даже смешение, наследуется от object
, Это означает, что любое использование множественного наследования естественным образом вызывает проблемы MRO.
Существуют способы заставить MRO с множественным наследованием работать в Python, в частности, функцию super(), но это означает, что вам нужно выполнить всю иерархию классов, используя super(), и понять процесс управления значительно сложнее.
Возможно, пара примеров поможет.
Если вы создаете класс и хотите, чтобы он действовал как словарь, вы можете определить все различные __ __
методы необходимы. Но это немного больно. В качестве альтернативы вы можете просто определить несколько и наследовать (в дополнение к любому другому наследованию) от UserDict.DictMixin
(переехал в collections.DictMixin
в py3k). Это приведет к автоматическому определению всех остальных словаря API.
Второй пример: инструментарий графического интерфейса пользователя wxPython позволяет создавать элементы управления списком с несколькими столбцами (как, например, отображение файла в проводнике Windows). По умолчанию эти списки являются довольно простыми. Вы можете добавить дополнительные функции, такие как возможность сортировки списка по определенному столбцу, щелкнув заголовок столбца, унаследовав от ListCtrl и добавив соответствующие миксины.
Это не пример Python, но в языке программирования D термин mixin
используется для обозначения конструкции, используемой почти таким же образом; добавив кучу вещей в класс.
В D (который, кстати, не делает MI) это делается путем вставки шаблона (подумайте о синтаксически осведомленных и безопасных макросах, и вы будете близки) в область действия. Это позволяет использовать одну строку кода в классе, структуре, функции, модуле или любом другом объекте для расширения до любого количества объявлений.
OP упомянул, что он / она никогда не слышал о mixin в C++, возможно, это потому, что они называются Curily Recurring Template Pattern (CRTP) в C++. Также @Ciro Santilli отметил, что mixin реализован через абстрактный базовый класс в C++. В то время как абстрактный базовый класс может использоваться для реализации mixin, это является избыточным, поскольку функциональность виртуальной функции во время выполнения может быть достигнута с использованием шаблона во время компиляции без накладных расходов на поиск виртуальной таблицы во время выполнения.
Шаблон CRTP подробно описан здесь
Я преобразовал пример Python в ответе @Ciro Santilli в C++, используя шаблонный класс ниже:
#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;
}
mixin дает возможность добавить функциональность в класс, то есть вы можете взаимодействовать с методами, определенными в модуле, включив модуль в желаемый класс. Хотя ruby не поддерживает множественное наследование, но предоставляет mixin как альтернативу для достижения этой цели.
Вот пример, который объясняет, как множественное наследование достигается с помощью 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
Я просто использовал Python Mixin для реализации модульного тестирования Python Milters. Обычно milter разговаривает с MTA, что затрудняет юнит-тестирование. Тестовый миксин переопределяет методы, которые общаются с MTA, и вместо этого создает моделируемую среду, управляемую тестовыми примерами.
Итак, вы берете немодифицированное приложение milter, такое как spfmilter, и mixin TestBase, например:
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)
Затем используйте TestMilter в тестовых случаях для приложения 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='good@example.com')
self.assertEqual(rc,Milter.CONTINUE)
milter.close()
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
Может быть, пример из ruby может помочь:
Вы можете включить миксин Comparable
и определить одну функцию "<=>(other)"
Mixin предоставляет все эти функции:
<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)
Это делает это, вызывая <=>(other)
и вернуть правильный результат.
"instance <=> other"
возвращает 0, если оба объекта равны, меньше 0, если instance
больше чем other
и больше 0, если other
больше.
Я читал, что у вас есть фон AC#. Так что хорошей отправной точкой может быть смешанная реализация для.NET.
Возможно, вы захотите проверить проект codeplex на http://remix.codeplex.com/
Смотрите ссылку на симпозиум lang.net, чтобы получить обзор. Еще больше информации о документации можно найти на странице кодекса.
С уважением Стефан