В чем разница между классами mixin и стандартным множественным наследованием в python [duplicate]

Чтобы получить временную часть в формате hh:MM:ss, вы можете использовать это регулярное выражение:

(Это было упомянуто выше в том же сообщении кем-то, спасибо за это.)

    var myDate = new Date().toTimeString().replace(/.*(\d{2}:\d{2}:\d{2}).*/, "$1");
    console.log(myDate)

733
задан Aaron Hall 25 March 2016 в 16:16
поделиться

15 ответов

Mixin - это особый вид множественного наследования. Существуют две основные ситуации, в которых используются миксины:

  1. Вы хотите предоставить множество дополнительных функций для класса.
  2. Вы хотите использовать одну конкретную функцию в партии разных классов.

Для примера номера один рассмотрим систему запросов и ответов werkzeug . Я могу сделать простой старый объект запроса, сказав:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

Если я хочу добавить поддержку заголовка accept, я бы сделал это

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. То есть, класс, вероятно, будет создан для самостоятельной работы.

543
ответ дан dalore 24 August 2018 в 04:47
поделиться

Что отличает mixin от множественного наследования? Это только вопрос семантики?

Смесин - это ограниченная форма множественного наследования. В некоторых языках механизм добавления mixin к классу несколько отличается (в терминах синтаксиса) от наследования.

В контексте Python, особенно, mixin является родительским классом, который предоставляет функциональные возможности для подклассы, но не предназначены для создания самого себя.

Что может заставить вас сказать: «Это просто множественное наследование, а не просто mixin», если класс, который может быть запутан для 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 предназначены для создания и использования самостоятельно. Однако, подклассифицируя их оба, мы можем иметь счетчик, который упорядочен и повторно использует код в каждом объекте.

Это мощный способ повторного использования кода, но также может быть проблематичным. Если окажется, что в одном из объектов есть ошибка, исправление без забот может создать ошибку в подклассе.

Пример Mixin

Микшины обычно рекламируются как способ повторного использования кода без потенциальных проблем связи, которые могут иметь совместное множественное наследование, например OrderedCounter. Когда вы используете mixins, вы используете функциональные возможности, которые не так тесно связаны с данными.

В отличие от вышеприведенного примера, mixin не предназначен для использования сам по себе. Он предоставляет новую или различную функциональность.

Например, стандартная библиотека имеет пару миксинов в библиотеке socketserver .

Forking и потоковые версии каждого типа сервера могут быть созданы с использованием этих классов смешения. Например, ThreadingUDPServer создается следующим образом:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

Класс mix-in приходит первым, поскольку он переопределяет метод, определенный в 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)
11
ответ дан Aaron Hall 24 August 2018 в 04:47
поделиться

Это не пример Python, но в языке программирования D термин mixin используется для ссылки на конструкцию, используемую почти одинаково; добавив кучу вещей в класс.

В D (который, кстати, не делает MI) это делается путем вставки шаблона (думаю, что синтаксически осведомленные и безопасные макросы и вы будете близки) в область. Это позволяет использовать одну строку кода в классе, структуре, функции, модуле или любом другом, чтобы расширять любое количество объявлений.

6
ответ дан BCS 24 August 2018 в 04:47
поделиться

OP упомянул, что он никогда не слышал о mixin в C ++, возможно, это потому, что они называются Curiously 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;
}
2
ответ дан bigdata2 24 August 2018 в 04:47
поделиться

Я бы посоветовал не смешивать в новый код Python, если вы можете найти какой-либо другой способ для него (например, композиция вместо наследования или просто методы клонирования обезьян в свои собственные классы)

В классах старого стиля вы можете использовать mix-ins как способ захвата нескольких методов из другого класса. Но в мире нового стиля все, даже смешанное, наследуется от object. Это означает, что любое использование множественного наследования естественно вводит проблемы MRO .

Существуют способы сделать работу MRO с множественным наследованием в Python, особенно в функции super (), но это означает, что вы должны выполнять всю свою иерархию классов с помощью функции super (), и значительно сложнее понять поток управления.

11
ответ дан bobince 24 August 2018 в 04:47
поделиться

Этот ответ направлен на объяснение mixins примерами, которые:

  • самодостаточны: короткие, без необходимости знать какие-либо библиотеки, чтобы понять пример.
  • в Python, а не на других языках. Понятно, что были примеры из других языков, таких как Ruby, поскольку этот термин гораздо более распространен в этих языках, но это поток Python .

It также должен рассмотреть спорный вопрос:

Требуется ли множественное наследование или не охарактеризовать mixin?

Определения

У меня еще нет чтобы увидеть цитату из «авторитетного» источника, четко говорящего о том, что такое mixin в Python.

Я видел 2 возможных определения mixin (если их следует рассматривать как отличающиеся от других подобных понятий, таких как абстрактные базовые классы), и люди не полностью согласны с тем, какой из них правильный.

Консенсус может различаться между разными языками.

Определение 1: отсутствие множественного наследования

Mixin - это класс, так что в некотором методе класса используется метод, который не определен в классе.

Поэтому класс не предназначен для создания экземпляра, а скорее s как основной класс. В противном случае экземпляр имел бы методы, которые нельзя вызвать без привлечения исключения.

Ограничение, которое добавляют некоторые источники, состоит в том, что класс не может содержать данные, только методы, но я не понимаю, почему это необходимо , На практике, однако, многие полезные миксины не имеют никаких данных, а базовые классы без данных проще использовать.

Классическим примером является реализация всех операторов сравнения только из <= и == :

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: множественное наследование

Mixin - это шаблон проектирования, в котором какой-либо метод базового класса использует метод, который он не определяет, и этот метод предполагается реализовать другим базовым классом , а не по производному, как в определении 1.

Термин mixin class относится к базовым классам, которые предназначены для использования в этом шаблоне проектирования (TODO те, которые используют этот метод, или те которые его реализуют?)

Нелегко решить, является ли данный класс микшированием или нет: метод может быть просто реализован в производном классе, и в этом случае мы вернемся к определению 1. Вы должны рассмотреть t авторские намерения.

Этот шаблон интересен тем, что можно рекомбинировать функциональные возможности с различными вариантами базовых классов:

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

At официальный документ для collection.abc в документации явно используется термин Методы Mixin .

В нем указано, что если класс:

  • реализует __next__
  • наследуется от одного класса Iterator

, тогда класс получает метод __iter__ mixin бесплатно.

Поэтому, по крайней мере, в этой точке документации, mixin не требует множественного наследования и согласуется с определением 1.

Документация может быть, конечно, противоречивой в разных точках, а другие важные библиотеки Python могут использовать другое определение в своей документации.

На этой странице также используется термин Set mixin, в котором четко указано, что такие классы, как Set и Iterator, могут называются классами Миксина.

На других языках

  • Ruby: Очевидно, не требуется множественное наследование для mixin, как указано в основных справочниках, таких как Programming Ruby и The Ruby programming Язык
  • C ++: метод, который не реализован, является чистым виртуальным методом. Определение 1 совпадает с определением абстрактного класса (класса, который имеет чистый виртуальный метод). Этот класс не может быть создан. Определение 2 возможно с виртуальным наследованием: Множественное наследование от двух производных классов
122
ответ дан Community 24 August 2018 в 04:47
поделиться

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
5
ответ дан Ernest Friedman-Hill 24 August 2018 в 04:47
поделиться

Может быть, пример из ruby ​​может помочь:

Вы можете включить mixin Comparable и определить одну функцию "<=>(other)", mixin предоставляет все эти функции:

<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)

Он делает это, вызывая <=>(other) и вернув правильный результат.

"instance <=> other" возвращает 0, если оба объекта равны, меньше 0, если instance больше other и больше, чем 0, если other больше.

6
ответ дан Georg Schölly 24 August 2018 в 04:47
поделиться

Я думаю о них как о дисциплинированном способе использования множественного наследования, потому что в конечном счете mixin - это еще один класс python, который (может) будет следовать соглашениям о классах, которые называются mixins.

Мое понимание соглашения, которые управляют тем, что вы бы назвали Mixin, состоят в том, что Mixin:

  • добавляет методы, но не переменные экземпляра (константы класса в порядке)
  • наследует только от object ( в Python)

Таким образом, он ограничивает потенциальную сложность множественного наследования и позволяет легко отслеживать поток вашей программы, ограничивая, где вы должны смотреть (по сравнению с полным множественным наследованием ). Они похожи на рубиновые модули.

Если я хочу добавить переменные экземпляра (с большей гибкостью, чем допускается одиночным наследованием), то я склонен идти на композицию.

Сказав, что , Я видел классы, называемые XYZMixin, которые имеют переменные экземпляра.

26
ответ дан Hamish Downer 24 August 2018 в 04:47
поделиться

Возможно, несколько примеров помогут.

Если вы создаете класс и хотите, чтобы он работал как словарь, вы можете определить все различные __ __ методы, необходимые. Но это немного боль. В качестве альтернативы вы можете просто определить несколько и наследовать (в дополнение к любому другому наследованию) из UserDict.DictMixin (перемещен в collections.DictMixin в py3k). Это приведет к автоматическому определению всего остального словаря api.

Второй пример: набор инструментов GUI wxPython позволяет создавать элементы управления списком с несколькими столбцами (например, отображение файла в Windows Explorer). По умолчанию эти списки довольно простые. Вы можете добавить дополнительные функции, такие как возможность сортировки списка по определенному столбцу, щелкнув заголовок столбца, наследуя от ListCtrl и добавляя соответствующие микшины.

8
ответ дан John Fouhy 24 August 2018 в 04:47
поделиться

Mixins - это концепция в программировании, в которой класс предоставляет функциональные возможности, но не предназначен для использования для создания экземпляра. Основная цель Mixins - предоставить функциональные возможности, которые являются автономными, и было бы лучше, если бы сами микстины не имели наследования с другими миксинами, а также избегали состояния. В таких языках, как Ruby, существует некоторая поддержка прямого языка, но для Python этого нет. Тем не менее, вы могли использовать многоуровневое наследование для выполнения функций, предоставляемых в Python.

Я смотрел это видео http://www.youtube.com/watch?v=v_uKI2NOLEM для понимания основ миксинов. Для новичков очень полезно понять основы миксинов и их работу, а также проблемы, с которыми вы можете столкнуться при их реализации.

Википедия по-прежнему остается лучшей: http: //en.wikipedia .org / вики / Mixin

19
ответ дан lakesh 24 August 2018 в 04:47
поделиться
198
ответ дан Randolpho 24 August 2018 в 04:47
поделиться

Я думаю, что здесь были хорошие объяснения, но я хотел представить еще одну перспективу.

В Scala вы можете делать mixins, как описано здесь, но очень интересно, что микшины на самом деле 'fused' вместе, чтобы создать новый класс класса для наследования. По сути, вы не наследуете от нескольких классов / mixins, а скорее генерируете новый тип класса со всеми свойствами mixin для наследования. Это имеет смысл, поскольку Scala основана на JVM, где в настоящее время не поддерживается многократное наследование (с Java 8). Этот тип типа mixin, кстати, является специальным типом, называемым Trait в Scala.

Он намекает на способ определения класса: класс NewClass расширяет FirstMixin с помощью SecondMixin с ThirdMixin ...

Я не уверен, что интерпретатор CPython делает то же самое (класс-состав mixin), но я не удивлюсь. Кроме того, исходя из фона C ++, я бы не назвал ABC или «интерфейс» эквивалентным mixin - это аналогичная концепция, но расходящаяся в использовании и реализации.

8
ответ дан SilentDirge 24 August 2018 в 04:47
поделиться

Я читал, что у вас есть c # background. Поэтому хорошей отправной точкой может быть реализация mixin для .NET.

Возможно, вы захотите проверить проект codeplex в http://remix.codeplex.com/

Просмотрите ссылку lang.net Symposium, чтобы получить обзор. Еще есть информация о документации на странице Codeplex.

рассматривает Stefan

3
ответ дан Stefan Papp 24 August 2018 в 04:47
поделиться

Я просто использовал микс python для реализации модульного тестирования для python milters. Как правило, milter разговаривает с MTA, что затрудняет тестирование модулей. Контрольный mixin переопределяет методы, которые говорят с 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 редакция = 1.6 & амп;? = вид разметки

5
ответ дан Stuart Gathman 24 August 2018 в 04:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: