Co to jest mixin i dlaczego są przydatne?

W "Programowanie Pythona" Mark Lutz wspomina "mixins". Jestem z tła C / C++/C# i jeszcze nie słyszałem tego określenia. Co to jest mixin?

Czytając między wierszami tego przykładu (do którego podlinkowałem, ponieważ jest dość długi), zakładam, że jest to przypadek użycia dziedziczenia wielokrotnego do rozszerzenia klasy w przeciwieństwie do 'właściwego' podklasowania. Czy to prawda?

Dlaczego miałbym to robić, a nie wprowadzać nową funkcjonalność do podklasa? Dlaczego podejście Mixin / multiple inheritance byłoby lepsze niż stosowanie kompozycji?

Co odróżnia Mixin od dziedziczenia wielokrotnego? Czy to tylko kwestia semantyki?

Author: Aaron Hall, 2009-02-10

16 answers

Mixin jest szczególnym rodzajem dziedziczenia wielokrotnego. Istnieją dwie główne sytuacje, w których stosuje się mixiny:

  1. chcesz zapewnić wiele opcjonalnych funkcji dla klasy.
  2. chcesz użyć jednej konkretnej funkcji w wielu różnych klasach.

Dla przykładu numer jeden, rozważ werkzeug ' s request and response system . Mogę zrobić zwykły stary obiekt request mówiąc:

from werkzeug import BaseRequest

class Request(BaseRequest):
    pass

Jeśli chcę dodać obsługę nagłówka accept, zrobiłbym że

from werkzeug import BaseRequest, AcceptMixin

class Request(AcceptMixin, BaseRequest):
    pass

Jeśli chciałem utworzyć obiekt request obsługujący nagłówki accept, etags, uwierzytelnianie i obsługę user agent, mogłem to zrobić:

from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin

class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
    pass

Różnica jest subtelna, ale w powyższych przykładach klasy mixin nie zostały stworzone do samodzielnego działania. W bardziej tradycyjnym dziedziczeniu wielokrotnym, AuthenticationMixin (na przykład) prawdopodobnie byłoby czymś bardziej podobnym do Authenticator. Oznacza to, że Klasa prawdopodobnie zostałaby zaprojektowana, aby stać na własną rękę.

 768
Author: Jason Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-04 13:12:37

Po pierwsze, należy zauważyć, że mixiny istnieją tylko w językach o wielu dziedziczeniach. Nie można zrobić mixin w Javie lub C#.

Zasadniczo mixin jest samodzielnym typem bazowym, który zapewnia ograniczoną funkcjonalność i rezonans polimorficzny dla klasy potomnej. Jeśli myślisz w C#, pomyśl o interfejsie, którego nie musisz faktycznie implementować, ponieważ jest już zaimplementowany; po prostu dziedziczysz z niego i korzystasz z jego funkcjonalności.

Mieszańce mają zazwyczaj wąski zakres i nie ma być przedłużony.

[edytuj -- dlaczego:]

Przypuszczam, że powinienem się zająć dlaczego, skoro pytasz. Dużą korzyścią jest to, że nie musisz robić tego sam w kółko. W C#, największe miejsce, gdzie Mixin może skorzystać Może być z Disposal pattern . Za każdym razem, gdy implementujesz IDisposable, prawie zawsze chcesz podążać za tym samym wzorcem, ale w końcu piszesz i ponownie piszesz ten sam podstawowy kod z niewielkimi zmianami. Gdyby istniała możliwość przedłużenia Utylizacja mixin, możesz zaoszczędzić sobie dużo dodatkowego pisania.

[edytuj 2 -- aby odpowiedzieć na inne pytania]

Co odróżnia Mixin od dziedziczenia wielokrotnego? Czy to tylko kwestia semantyki?

Tak. Różnica między mixinem a standardowym dziedziczeniem wielokrotnym jest tylko kwestią semantyki; klasa, która ma wiele dziedziczeń, może wykorzystać mixin jako część tego wielokrotnego dziedziczenia.

Celem mixin jest stworzenie typu, który może być "mieszany" z dowolnym innym typem poprzez dziedziczenie bez wpływu na typ dziedziczący, jednocześnie oferując pewne korzystne funkcje dla tego typu.

Ponownie pomyśl o interfejsie, który jest już zaimplementowany.

Ja osobiście nie używam mixinów, ponieważ rozwijam się głównie w języku, który ich nie obsługuje, więc mam naprawdę trudny czas, wymyślając przyzwoity przykład, który dostarczy po prostu " ahah!"chwila dla Ciebie. Ale spróbuję jeszcze raz. Użyję przykład, który jest wymyślony-większość języków już dostarcza tę funkcję w jakiś sposób - ale to, miejmy nadzieję, wyjaśni, w jaki sposób mixiny mają być tworzone i używane. Zaczyna się:

Załóżmy, że masz typ, który chcesz mieć możliwość serializacji do i z XML. Chcesz, aby Typ dostarczał metodę "ToXML", która zwraca łańcuch zawierający fragment XML z wartościami danych typu oraz "FromXML", który pozwala typowi na rekonstrukcję wartości danych z fragmentu XML w sznurku. Ponownie, jest to wymyślony przykład, więc być może używasz strumienia plików lub klasy XML Writer z biblioteki uruchomieniowej Twojego języka... nieważne. Chodzi o to, że chcesz serializować obiekt do XML i uzyskać nowy obiekt z XML.

Innym ważnym punktem w tym przykładzie jest to, że chcesz to zrobić w sposób ogólny. Nie chcesz implementować metody "ToXML" i "FromXML" dla każdego typu, który chcesz serializować, chcesz jakieś ogólne środki zapewnienie, że Twój typ to zrobi i to po prostu działa. Chcesz ponownie użyć kodu.

Jeśli twój język go obsługiwał, możesz utworzyć XmlSerializable mixin, aby wykonać swoją pracę za Ciebie. Ten typ implementuje metody ToXML i fromxml. Przy użyciu jakiegoś mechanizmu, który nie jest ważny dla przykładu, byłby w stanie zebrać wszystkie niezbędne dane z dowolnego typu, z którym jest zmieszany, aby zbudować fragment XML zwracany przez ToXML i byłby w stanie go przywrócić dane po wywołaniu FromXML.

I.. to wszystko. Aby go użyć, musisz mieć dowolny typ, który musi być serializowany do XML inheritate z XmlSerializable. Ilekroć potrzebujesz serializacji lub deserializacji tego typu, po prostu wywołaj ToXML lub FromXML. W rzeczywistości, ponieważ XmlSerializable jest pełnoprawnym typem i polimorficznym, można przypuszczać, że można zbudować serializator dokumentów, który nie wie nic o oryginalnym typie, akceptując tylko, powiedzmy, tablicę typów xmlserializable.

Teraz wyobraź sobie użycie tego scenariusza do innych rzeczy, jak tworzenie Mixin, który zapewnia, że każda klasa, która miesza go w logach każdego wywołania metody, lub mixin, który zapewnia transakcyjność do typu, który miesza go w. Lista może być długa.

Jeśli po prostu myślisz o mixinie jako małym typie bazowym zaprojektowanym w celu dodania niewielkiej funkcjonalności do typu bez wpływu w inny sposób na ten typ, to jesteś złoty.

Miejmy nadzieję. :)

 252
Author: Randolpho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-13 20:53:07

Ta odpowiedź ma na celu wyjaśnienie mixins z przykładami , które są:

  • Self-contained : krótki, bez potrzeby znajomości bibliotek, aby zrozumieć przykład.

  • W Pythonie , a nie w innych językach.

    Zrozumiałe jest, że były przykłady z innych języków, takich jak Ruby, ponieważ termin ten jest znacznie bardziej powszechny w tych językach, ale jest to wątek Python .

Zastanów się również nad kontrowersyjnym pytaniem:

Czy wielokrotne dziedziczenie jest konieczne, czy nie do scharakteryzowania mixin?

Definicje

Nie widziałem jeszcze cytatu z" autorytatywnego " źródła mówiącego wyraźnie, czym jest mixin w Pythonie.

Widziałem 2 możliwe definicje mixin (jeśli mają być uznane za różne od innych podobnych pojęć, takich jak abstrakcyjne klasy bazowe), a ludzie nie do końca zgadzają się, która z nich jest zgadza się.

Konsensus może się różnić w zależności od języka.

Definicja 1: Brak dziedziczenia wielokrotnego

Mixin jest klasą taką, że niektóre metody klasy używają metody, która nie jest zdefiniowana w klasie.

Dlatego klasa nie jest przeznaczona do tworzenia instancji, ale raczej służy jako klasa bazowa. W przeciwnym razie instancja miałaby metody, których nie można wywołać bez wywołania wyjątku.

Ograniczenie, które niektóre źródła dodają, jest takie, że klasa może nie zawierać danych, tylko metody, ale nie widzę powodu, dla którego jest to konieczne. W praktyce jednak wiele użytecznych mixinów nie ma żadnych danych, a klasy bazowe bez danych są prostsze w użyciu.

Klasycznym przykładem jest implementacja wszystkich operatorów porównania z tylko <= i ==:

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 

Ten konkretny przykład można było osiągnąć za pomocą dekoratora functools.total_ordering(), ale gra tutaj polegała na odkryciu koła na nowo:

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)

Definicja 2: wielokrotność dziedziczenie

Mixin jest wzorcem projektowym, w którym pewna metoda klasy bazowej używa metody, której nie definiuje, a ta metoda ma być zaimplementowana przez inną klasę bazową , a nie przez pochodną, jak w definicji 1.

Termin Klasa mixin odnosi się do klas bazowych, które mają być używane w tym wzorze projektowym (do tych, które używają metody, czy tych, które ją implementują?)

Nie jest łatwo zdecydować, czy dana klasa jest mixinem czy Nie: metoda może być po prostu zaimplementowana na klasie pochodnej, w którym to przypadku wracamy do definicji 1. Trzeba wziąć pod uwagę intencje autora.

Ten wzór jest interesujący, ponieważ możliwe jest połączenie funkcji z różnymi wyborami klas bazowych:

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

Autorytatywne wystąpienia Pythona

W oficjalnym dokumencie dla kolekcji.abc dokumentacja wyraźnie używa terminu Mixin Metody .

Stwierdza, że jeśli Klasa:

  • Narzędzia __next__
  • dziedziczy z jednej klasy Iterator

Wtedy Klasa dostaje __iter__ metoda mixin za darmo.

Dlatego przynajmniej w tym punkcie dokumentacji, mixin nie wymaga wielokrotnego dziedziczenia i jest spójny z definicją 1.

Dokumentacja może być oczywiście sprzeczna w różnych punktach, a inne ważne Python biblioteki mogą używać innej definicji w swojej dokumentacji.

Ta strona używa również terminu Set mixin, co wyraźnie sugeruje, że klasy takie jak Set i Iterator mogą być nazywane klasami Mixin.

W innych językach

  • Ruby: oczywiście nie wymaga wielokrotnego dziedziczenia dla mixin, jak wspomniano w głównych podręcznikach, takich jak Programowanie Ruby i język programowania Ruby
  • C++: a virtual metoda, która is set =0 jest czystą metodą wirtualną.

    Definicja 1 pokrywa się z definicją klasy abstrakcyjnej (klasy, która ma czystą metodę wirtualną). Tej klasy nie można utworzyć instancji.

    Definicja 2 jest możliwa przy dziedziczeniu wirtualnym: dziedziczenie wielokrotne z dwóch klas pochodnych

 189
Author: Ciro Santilli TRUMP BAN IS BAD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-16 21:45:45

Myślę o nich jako o zdyscyplinowanym sposobie używania wielu dziedziczeń - ponieważ ostatecznie Mixin jest po prostu kolejną klasą Pythona, która (może) podąża za konwencjami dotyczącymi klas, które są nazywane mixins.

Moje rozumienie konwencji, które rządzą czymś, co można nazwać Mixinem, jest takie, że Mixin:

  • dodaje metody, ale nie zmienne instancji (stałe klasy są w porządku)
  • dziedziczy tylko z object (w Pythonie)

W ten sposób ogranicza potencjał złożoność dziedziczenia wielokrotnego i ułatwia śledzenie przepływu programu poprzez ograniczenie miejsca, w którym trzeba szukać (w porównaniu do pełnego dziedziczenia wielokrotnego). Są one podobne do modułów ruby .

Jeśli chcę dodać zmienne instancji (z większą elastycznością, niż pozwala na to pojedyncze dziedziczenie), zazwyczaj wybieram kompozycję.

Powiedziawszy to, widziałem klasy zwane XYZMixin, które mają zmienne instancji.

 41
Author: Hamish Downer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-21 12:45:16

Co odróżnia Mixin od dziedziczenia wielokrotnego? Czy to tylko kwestia semantyki?

Mixin jest ograniczoną formą dziedziczenia wielokrotnego. W niektórych językach mechanizm dodawania mixin do klasy jest nieco inny (pod względem składni) od mechanizmu dziedziczenia.

W kontekście Pythona, Mixin jest klasą nadrzędną, która zapewnia funkcjonalność podklasom, ale nie jest przeznaczona do tworzenia instancji.

Co może spowodować można powiedzieć, "to jest po prostu wielokrotne dziedziczenie, a nie naprawdę mixin", jeśli klasa, która może być mylona z mixin, może być faktycznie utworzona i użyta - więc rzeczywiście jest to semantyczna i bardzo realna różnica.

Przykład dziedziczenia wielokrotnego

Jest to przykład,

, Z dokumentacji , jest to 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),)

To podklasa zarówno Counter, jak i OrderedDict z modułu collections.

Zarówno Counter jak i OrderedDict mają być utworzone i używane samodzielnie. Jednak poprzez podklasowanie ich obu, możemy mieć licznik, który jest uporządkowany i ponownie wykorzystuje kod w każdym obiekcie.

Jest to potężny sposób na ponowne użycie kodu, ale może być również problematyczny. Jeśli okaże się, że w jednym z obiektów jest błąd, naprawienie go bez troski może spowodować błąd w podklasie.

Przykład Mixin

Mixiny są zwykle promowane jako sposób na ponowne użycie kodu bez potencjalnych problemów ze sprzężeniem, które współpracują dziedziczenie wielokrotne, jak Zamawiający, mogło mieć. Gdy używasz mixins, używasz funkcjonalności, która nie jest tak ściśle powiązana z danymi.

W przeciwieństwie do powyższego przykładu, Mixin nie jest przeznaczony do stosowania w monoterapii. Zapewnia nową lub inną funkcjonalność.

Na przykład Biblioteka standardowa ma kilka mixinów w bibliotece socketserver .

Można tworzyć wersje Forkingowe i threadingowe każdego typu serwera korzystanie z tych mieszanek klasy. Na przykład, ThreadingUDPServer jest utworzony w następujący sposób:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

Klasa mix-in jest pierwsza, ponieważ nadpisuje metodę zdefiniowaną w UDPServer. Ustawienie różnych atrybutów zmienia również zachowanie podstawowy mechanizm serwera.

W tym przypadku metody mixin nadpisują metody z definicji obiektu UDPServer, aby umożliwić współbieżność.

Overridden metoda wydaje się być {[13] } i zapewnia również inną metodę, process_request_thread. Oto kod źródłowy :

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()

Wymyślony Przykład

Jest to mieszanka, która jest głównie do celów demonstracyjnych - większość obiektów będzie ewoluować poza użyteczność tego repr: {]}
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)
          )

I użycie byłoby:

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__()

I użycie:

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)
 32
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-13 22:00:53

Mixins jest pojęciem w programowaniu, w którym Klasa dostarcza funkcjonalności, ale nie jest przeznaczona do tworzenia instancji. Głównym celem Mixins jest zapewnienie funkcjonalności, które są samodzielne i najlepiej byłoby, gdyby same mixins nie mają dziedziczenia z innymi mixins, a także uniknąć stanu. W językach takich jak Ruby, istnieje pewne bezpośrednie wsparcie językowe, ale w Pythonie nie ma. można jednak użyć dziedziczenia wieloklasowego do wykonania funkcjonalności dostarczanej w Python.

Oglądałem ten filmik http://www.youtube.com/watch?v=v_uKI2NOLEM aby zrozumieć podstawy mixins. Jest to bardzo przydatne dla początkujących, aby zrozumieć podstawy mixins i jak działają i problemy, które mogą napotkać w ich realizacji.

Wikipedia jest nadal najlepsza: http://en.wikipedia.org/wiki/Mixin

 30
Author: lakesh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-13 07:29:18

Myślę, że poprzednie odpowiedzi bardzo dobrze definiowały czym sąMixiny . Jednakże, aby lepiej je zrozumieć, warto porównać MixIns z klasy abstrakcyjne oraz interfejsy z punktu widzenia kodu/implementacji:

1. Klasa Abstrakcyjna

  • klasa, która musi zawierać jedną lub więcej metod abstrakcyjnych

  • klasa abstrakcyjna can zawiera Stany (zmienne instancji) i metody nieabstraktowe

2. Interfejs

  • Interfejs zawiera tylko metody abstrakcyjne (bez metod nieabstraktowych i bez stanu wewnętrznego)

3. MixIns

  • Mixiny (Jak Interfejsy) nie zawierają stanu wewnętrznego (zmiennych instancji)
  • Mixiny zawierają jedną lub więcej metod nieabstraktowych (mogązawierać metody nieabstraktowe w przeciwieństwie do interfejsów)

W np. Pythonie są to tylko konwencje, ponieważ wszystkie powyższe są zdefiniowane jako class es. Jednak wspólną cechą obu klas abstrakcyjnych, interfejsów i Mixinów jest to, że nie powinny istnieć same, tzn. nie powinny być tworzone instancyjnie.

 12
Author: Tomasz Bartkowiak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-17 12:24:46

Myślę, że było tu kilka dobrych wyjaśnień, ale chciałem podać inną perspektywę.

W Scali, możesz robić mixiny, jak zostało to opisane tutaj, ale co jest bardzo interesujące, to to, że mixiny są faktycznie "zespolone" ze sobą, aby stworzyć nowy rodzaj klasy, z której można dziedziczyć. Zasadniczo, nie dziedziczysz z wielu klas/mixinów, ale raczej generujesz nowy rodzaj klasy ze wszystkimi właściwościami mixinu do dziedziczenia. Ma to sens, ponieważ Scala opiera się na JVM, gdzie dziedziczenie wielokrotne nie jest obecnie obsługiwane(od Java 8). Ten typ klasy mixin, nawiasem mówiąc, jest specjalnym typem zwanym cechą w Scali.

Jest wskazana w sposobie definiowania klasy: Klasa NewClass rozszerza FirstMixin z SecondMixin z ThirdMixin ...

Nie jestem pewien, czy interpreter CPython robi to samo (Mixin class-composition), ale nie zdziwiłbym się. Również, wychodząc z tła C++, nie nazwałbym ABC lub "interfejsu" odpowiednikiem mixin-to pojęcie podobne, ale rozbieżne w użyciu i implementacji.

 11
Author: SilentDirge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-25 02:16:08

Odradzałbym mieszanie w nowym kodzie Pythona, jeśli można znaleźć jakieś inne rozwiązanie (takie jak skład zamiast dziedziczenia, czy po prostu łatanie małp do własnych klas), które nie jest o wiele trudniejsze.

W klasach w starym stylu możesz użyć mixów jako sposobu na pobranie kilku metod z innej klasy. Ale w świecie nowego stylu wszystko, nawet mieszanka, dziedziczy od object. Oznacza to, że każde użycie dziedziczenia Wielokrotnego w sposób naturalny wprowadza MRO issues .

Istnieją sposoby na to, aby MRO-dziedziczenie wielokrotne działało w Pythonie, przede wszystkim funkcja super (), ale oznacza to, że musisz wykonać całą hierarchię klas za pomocą super () i znacznie trudniej jest zrozumieć przepływ kontroli.

 9
Author: bobince,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-10 19:21:19

Może kilka przykładów pomoże.

Jeśli budujesz klasę i chcesz, aby działała jak słownik, możesz zdefiniować wszystkie potrzebne metody __ __. Ale to trochę boli. Alternatywnie, możesz po prostu zdefiniować kilka i dziedziczyć (oprócz dowolnego innego dziedziczenia) z UserDict.DictMixin (przeniesiony do collections.DictMixin w py3k). Spowoduje to automatyczne zdefiniowanie całej reszty słownika api.

Drugi przykład: GUI toolkit wxPython pozwala możesz tworzyć kontrolki listy z wieloma kolumnami (jak np. wyświetlanie plików w Eksploratorze Windows). Domyślnie te listy są dość proste. Możesz dodać dodatkowe funkcje, takie jak możliwość sortowania listy po określonej kolumnie, klikając na nagłówek kolumny, dziedzicząc z ListCtrl i dodając odpowiednie mixiny.

 9
Author: John Fouhy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-10 21:27:41

Nie jest to przykład Pythona, ale w języku programowania D termin mixin jest używane w odniesieniu do konstrukcji używanej w podobny sposób; dodawanie stosu rzeczy do klasy.

W D (który przy okazji nie robi MI) odbywa się to poprzez wstawienie szablonu (myśl składniowo świadome i bezpieczne makra, a będziesz blisko) do zakresu. Pozwala to na rozszerzenie pojedynczej linii kodu w klasie, strukturze, funkcji, module lub dowolnej innej na dowolną liczbę deklaracji.

 9
Author: BCS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-21 14:05:52

OP wspomniał, że nigdy nie słyszał o mixinie w C++, być może dlatego, że są one nazywane Curiously Recurring Template Pattern (CRTP) w C++. @Ciro Santilli wspomniał również, że mixin jest zaimplementowany przez abstrakcyjną klasę bazową w C++. Chociaż abstrakcyjna klasa bazowa może być używana do implementacji mixin, jest to przesada, ponieważ funkcjonalność funkcji wirtualnej w czasie wykonywania może być osiągnięta przy użyciu szablonu w czasie kompilacji bez narzutu wyszukiwania wirtualnej tabeli w czasie wykonywania.

CRTP wzór jest szczegółowo opisany tutaj

Przekonwertowałem przykład Pythona w odpowiedzi @Ciro Santilli na C++ używając poniższej klasy szablonów:

    #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));
        }
        protected:
            ComparableMixin() {}
    };

    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) ;
    //ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
    assert (i < j );
    assert (i != j);
    assert (j >  i);
    assert (j >= i);

    return 0;
}

EDIT: Dodano protected constructor w ComparableMixin tak, że można go tylko dziedziczyć, a nie tworzyć instancje. Zaktualizowano przykład, aby pokazać, w jaki sposób konstruktor chroniony spowoduje błąd kompilacji podczas tworzenia obiektu ComparableMixin.

 7
Author: bigdata2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-06-15 17:06:03

Może przykład z ruby może pomóc:

Możesz dołączyć mixin Comparable i zdefiniować jedną funkcję "<=>(other)", mixin dostarcza wszystkich tych funkcji:

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

Robi to poprzez wywołanie <=>(other) i zwrócenie właściwego wyniku.

"instance <=> other" zwraca 0, jeśli oba obiekty są równe, mniej niż 0, jeśli {[5] } jest większy niż other i więcej niż 0, Jeśli other jest większy.

 6
Author: Georg Schölly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-10 19:08:50

Mixin daje sposób na dodanie funkcjonalności w klasie, tzn. można wchodzić w interakcje z metodami zdefiniowanymi w module, włączając moduł do żądanej klasy. Chociaż ruby nie obsługuje wielokrotnego dziedziczenia, ale dostarcza mixin jako alternatywę, aby to osiągnąć.

Oto przykład, który wyjaśnia, w jaki sposób dziedziczenie wielokrotne jest osiągane za pomocą 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
 6
Author: Akash Soti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-31 12:08:04

Właśnie użyłem Pythona mixin zaimplementować testowanie jednostkowe dla milterów Pythona. Zwykle milter rozmawia z MTA, co utrudnia Testowanie jednostek. Test mixin nadpisuje metody, które rozmawiają z MTA i tworzą symulowane środowisko napędzane przez przypadki testowe.

Więc, bierzesz niezmodyfikowaną aplikację milter, jak spfmilter, i Mixin TestBase, jak to:

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)

Następnie, użyj TestMilter w przypadkach testowych dla milter Zastosowanie:

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

 6
Author: Stuart Gathman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-12 21:22:43

Czytałem, że masz c # tło. Tak więc dobrym punktem wyjścia może być implementacja mixin dla .NET.

Możesz sprawdzić projekt codeplex na http://remix.codeplex.com/

Obejrzyj lang.net link do Sympozjum, aby uzyskać przegląd. Na stronie codeplex jest jeszcze więcej informacji na temat dokumentacji.

Pozdrawiam Stefan

 3
Author: Stefan Papp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-23 10:16:56