В « Программировании Python » Марк Лутц упоминает «миксины». Я из C / C ++ / C # фона, и я не слышал этот термин раньше. Что такое миксин?
Читая между строк этого примера (который я связал, потому что он довольно длинный), я предполагаю, что это случай использования множественного наследования для расширения класса, а не для «правильного» подкласса. Это правильно?
Почему я хотел бы сделать это, а не помещать новую функциональность в подкласс? В этом отношении, почему подход смешанного / множественного наследования лучше, чем использование композиции?
Что отличает миксин от множественного наследования? Это просто вопрос семантики?
источник
Parent
класса иChild1
,Child2
,ChildN
подклассы внутри 3 библиотеки партии, и вы хотите настроенное поведение для всей семьи. В идеале вы хотели бы добавить такое поведениеParent
и надеяться, что сторонний разработчик библиотеки примет ваш запрос на извлечение. В противном случае вам придется реализовать свой собственныйclass NewBehaviorMixin
, а затем определить полный набор классов-class NewParent(NewBehaviorMixin, Parent): pass
class NewChildN(NewBehaviorMixin, ChildN): pass
Во-первых, вы должны заметить, что миксины существуют только в языках множественного наследования. Вы не можете сделать миксин в 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: нет множественного наследования
Миксин - это такой класс, что некоторый метод класса использует метод, который не определен в классе.
Поэтому класс не предназначен для создания экземпляра, а служит базовым классом. В противном случае экземпляр будет иметь методы, которые нельзя вызвать без вызова исключения.
Ограничение, которое добавляют некоторые источники, состоит в том, что класс может не содержать данных, только методы, но я не понимаю, почему это необходимо. Однако на практике многие полезные миксины не имеют данных, а базовые классы без данных проще в использовании.
Классическим примером является реализация всех операторов сравнения с только
<=
и==
:Этот конкретный пример мог быть реализован через
functools.total_ordering()
декоратор, но игра здесь состояла в том, чтобы заново изобрести колесо:Определение 2: множественное наследование
Миксин - это шаблон проектирования, в котором некоторый метод базового класса использует метод, который он не определяет, и этот метод предназначен для реализации другим базовым классом , а не производным, как в определении 1.
Термин класс mixin относится к базовым классам, которые предназначены для использования в этом шаблоне проектирования (TODO, которые используют метод, или те, которые его реализуют?)
Нелегко определить, является ли данный класс миксином или нет: метод может быть просто реализован в производном классе, и в этом случае мы вернемся к определению 1. Вы должны учитывать намерения автора.
Эта модель интересна тем, что можно комбинировать функции с различными вариантами выбора базовых классов:
Авторитетные появления Python
В официальной документации для collection.abc в документации явно используется термин Mixin Methods .
В нем говорится, что если класс:
__next__
Iterator
тогда класс получает
__iter__
метод mixin бесплатно.Поэтому, по крайней мере, в этом пункте документации, mixin не требует множественного наследования и согласуется с определением 1.
Разумеется, документация может быть противоречивой в разные моменты, и другие важные библиотеки Python могут использовать другое определение в своей документации.
На этой странице также используется термин
Set mixin
, который ясно указывает на то, что классы любятSet
иIterator
могут называться классами Mixin.На других языках
Ruby: Очевидно, что не требуется множественное наследование для mixin, как упоминалось в основных справочниках, таких как Programming Ruby и The Ruby Language Language.
C ++: метод, который не реализован, является чисто виртуальным методом.
Определение 1 совпадает с определением абстрактного класса (класса, который имеет чисто виртуальный метод). Этот класс не может быть создан.
Определение 2 возможно с виртуальным наследованием: множественное наследование от двух производных классов
источник
Я думаю о них как о дисциплинированном способе использования множественного наследования - потому что в конечном итоге mixin - это просто еще один класс python, который (может) следовать соглашениям о классах, которые называются mixins.
Мое понимание соглашений, которые управляют чем-то, что вы бы назвали миксином, таково, что миксин:
object
(в Python)Таким образом, он ограничивает потенциальную сложность множественного наследования и позволяет достаточно легко отслеживать поток вашей программы, ограничивая область поиска (по сравнению с полным множественным наследованием). Они похожи на модули ruby .
Если я хочу добавить переменные экземпляра (с большей гибкостью, чем допускается одиночным наследованием), я склоняюсь к компоновке.
Сказав это, я видел классы с именем XYZMixin, которые имеют переменные экземпляра.
источник
Mixins - это концепция в программировании, в которой класс предоставляет функциональные возможности, но он не предназначен для использования в экземплярах. Основная цель Mixins состоит в том, чтобы обеспечить функциональные возможности, которые являются автономными, и было бы лучше, если бы сами миксины не наследовали другие миксины и также избегали состояния. В таких языках, как Ruby, есть прямая языковая поддержка, но для Python - нет. Однако вы можете использовать наследование нескольких классов для выполнения функций, предоставляемых в Python.
Я смотрел это видео http://www.youtube.com/watch?v=v_uKI2NOLEM чтобы понять основы миксинов. Для новичка очень полезно понять основы миксинов и то, как они работают, и проблемы, с которыми вы можете столкнуться при их реализации.
Википедия по-прежнему лучшая: http://en.wikipedia.org/wiki/Mixin
источник
Mixin - это ограниченная форма множественного наследования. В некоторых языках механизм добавления mixin в класс немного отличается (с точки зрения синтаксиса) от механизма наследования.
В частности, в контексте Python, mixin - это родительский класс, который предоставляет функциональные возможности подклассам, но сам по себе не предназначен для реализации.
Что может заставить вас сказать, что «это просто множественное наследование, а не миксин», так это то, что класс, который может быть сбит с толку за миксин, действительно может быть создан и использован - так что это действительно семантическая и очень реальная разница.
Пример множественного наследования
Этот пример из документации является OrderedCounter:
Это подклассы и от
Counter
иOrderedDict
отcollections
модуля.Оба
Counter
иOrderedDict
предназначены для реализации и использования самостоятельно. Однако, подклассифицируя их обоих, мы можем получить счетчик, который упорядочен и повторно использует код в каждом объекте.Это мощный способ повторного использования кода, но он также может быть проблематичным. Если окажется, что в одном из объектов есть ошибка, ее исправление может привести к ошибке в подклассе.
Пример миксина
Миксины обычно рекламируются как способ повторного использования кода без потенциальных проблем связывания, которые могут возникнуть при совместном множественном наследовании, например, OrderedCounter. Когда вы используете миксины, вы используете функциональность, которая не так тесно связана с данными.
В отличие от приведенного выше примера, миксин не предназначен для самостоятельного использования. Это обеспечивает новую или другую функциональность.
Например, в стандартной библиотеке есть пара миксинов в
socketserver
библиотеке .В этом случае методы mixin переопределяют методы в
UDPServer
определении объекта, чтобы обеспечить параллелизм.Переопределяется метод , как представляется,
process_request
и он также предоставляет другой метод,process_request_thread
. Вот это из исходного кода :Придуманный пример
Это миксин, который в основном предназначен для демонстрации - большинство объектов будут развиваться за пределами полезности этого отчета:
и использование будет:
И использование:
источник
Я думаю, что здесь было несколько хороших объяснений, но я хотел представить другую точку зрения.
В 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.Второй пример: инструментарий GUI 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 ++, используя шаблонный класс ниже:
РЕДАКТИРОВАТЬ: Добавлен защищенный конструктор в ComparableMixin, так что он может быть только унаследован и не создан. Обновлен пример, чтобы показать, как защищенный конструктор будет вызывать ошибку компиляции при создании объекта ComparableMixin.
источник
Может быть, пример из ruby может помочь:
Вы можете включить миксин
Comparable
и определить одну функцию"<=>(other)"
, миксин предоставляет все эти функции:Он делает это, вызывая
<=>(other)
и возвращая правильный результат."instance <=> other"
возвращает 0, если оба объекта равны, меньше 0, еслиinstance
больше,other
и больше 0, еслиother
больше.источник
__lt__
как базовое, а не__cmp__
последнее, которое фактически не рекомендуется и не рекомендуется использовать. Мне кажется, проще использовать этот миксин вместо довольно сложных декораторов (часть functools ) - хотя этот может быть в состоянии более динамично реагировать на то, какие сравнения даются ...mixin дает возможность добавить функциональность в класс, т. е. вы можете взаимодействовать с методами, определенными в модуле, включив модуль в нужный класс. Хотя ruby не поддерживает множественное наследование, но предоставляет mixin как альтернативу для достижения этой цели.
Вот пример, который объясняет, как множественное наследование достигается с помощью mixin.
источник
Я просто использовал Python Mixin для реализации модульного тестирования Python Milters. Как правило, milter разговаривает с MTA, что затрудняет юнит-тестирование. Тестовый миксин переопределяет методы, которые общаются с MTA, и вместо этого создает моделируемую среду, управляемую тестовыми примерами.
Итак, вы берете немодифицированное приложение milter, такое как spfmilter, и mixin TestBase, например:
Затем используйте TestMilter в тестовых случаях для приложения milter:
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
источник
Я думаю, что предыдущие ответы очень хорошо определили, что такое MixIns . Однако, чтобы лучше понять их, было бы полезно сравнить MixIns с абстрактными классами и интерфейсами с точки зрения кода / реализации:
1. Абстрактный класс
Класс, который должен содержать один или несколько абстрактных методов
Абстрактный класс может содержать состояние (переменные экземпляра) и неабстрактные методы
2. Интерфейс
3. Смешивание
Например, в Python это просто соглашения, потому что все вышеперечисленное определено как
class
es. Тем не менее, общая особенность абстрактных классов, интерфейсов и MixIns заключается в том, что они не должны существовать сами по себе, т.е. не должны создаваться.источник
Я читал, что у вас есть фон AC #. Так что хорошей отправной точкой может быть смешанная реализация для .NET.
Возможно, вы захотите проверить проект codeplex на http://remix.codeplex.com/
Смотрите ссылку на симпозиум lang.net, чтобы получить обзор. Еще больше информации о документации можно найти на странице кодекса.
С уважением Стефан
источник