Цель этого ответа - объяснить миксины с примерами :
автономный : короткий, без необходимости знать какие-либо библиотеки для понимания примера.
на Python , но не на других языках.
Понятно, что были примеры из других языков, таких как Ruby, поскольку этот термин гораздо чаще встречается в этих языках, но это Python thread.
Следует также рассмотреть спорный вопрос:
Необходимо ли множественное наследование или нет для характеристики миксина?
Определения
Мне еще предстоит увидеть цитату из "авторитетного" источника, в которой четко сказано, что такое миксин в Python.
Я видел 2 возможных определения миксина (если их следует считать отличными от других подобных концепций, таких как абстрактные базовые классы), и люди не совсем согласны с тем, какое из них правильное.
Консенсус может отличаться для разных языков.
Определение 1: нет множественного наследования
Миксин - это такой класс, что некоторый метод класса использует метод, который не определен в классе.
Следовательно, этот класс не предназначен для создания экземпляра, а скорее служит базовым классом. В противном случае экземпляр будет иметь методы, которые не могут быть вызваны без вызова исключения.
Ограничение, которое добавляют некоторые источники, состоит в том, что класс может не содержать данные, только методы, но я не понимаю, почему это необходимо. Однако на практике многие полезные миксины не имеют данных, а базовые классы без данных проще в использовании.
Классическим примером является реализация всех операторов сравнения только с <=
и ==
:
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 class относится к базовым классам, которые предназначены для использования в этом шаблоне проектирования (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 в документации явно используется термин Методы смешивания .
В нем говорится, что если класс:
- орудия
__next__
- наследуется от одного класса
Iterator
тогда класс получает __iter__
метод mixin бесплатно.
Поэтому, по крайней мере, в этом пункте документации, mixin не требует множественного наследования и соответствует определению 1.
Документация, конечно, может быть противоречивой в разные моменты, и другие важные библиотеки Python могут использовать другое определение в своей документации.
На этой странице также используется термин Set mixin
, который ясно указывает на то, что классы, подобные Set
и Iterator
, можно назвать классами Mixin.
На других языках
Ruby: Очевидно, что не требуется множественное наследование для mixin, как упоминалось в основных справочниках, таких как Programming Ruby и Язык программирования Ruby
C ++: Метод, который не реализован, является чисто виртуальным методом.
Определение 1 совпадает с определением абстрактного класса (класса, который имеет чисто виртуальный метод).
Этот класс не может быть создан.
Определение 2 возможно с виртуальным наследованием: Множественное наследование от двух производных классов