W „ Programming Python ” Mark Lutz wspomina o „mixinach”. Pochodzę z środowisk C / C ++ / C # i nie słyszałem wcześniej tego terminu. Co to jest mixin?
Czytając między wierszami tego przykładu (do którego podłączyłem, ponieważ jest dość długi), przypuszczam, że jest to przypadek użycia wielokrotnego dziedziczenia w celu rozszerzenia klasy w przeciwieństwie do „właściwej” podklasy. Czy to jest poprawne?
Dlaczego miałbym to robić, zamiast umieszczać nową funkcjonalność w podklasie? Jeśli o to chodzi, dlaczego podejście mieszania / wielokrotnego dziedziczenia byłoby lepsze niż stosowanie kompozycji?
Co odróżnia mixin od wielokrotnego dziedziczenia? Czy to tylko kwestia semantyki?
źródło
Parent
klasy iChild1
,Child2
,ChildN
podklasy wewnątrz 3rd biblioteki partii, a chcesz dostosowaną zachowanie dla całej rodziny. Idealnie chciałbyś dodać takie zachowanieParent
i mam nadzieję, że zewnętrzny programista biblioteki przyjmie Twoje żądanie ściągnięcia. W przeciwnym razie będziesz musiał zaimplementować własneclass NewBehaviorMixin
, a następnie zdefiniować pełny zestaw klas opakowań, takich jakclass NewParent(NewBehaviorMixin, Parent): pass
iclass NewChildN(NewBehaviorMixin, ChildN): pass
, itp. (PS: Czy znasz lepszy sposób?)Po pierwsze, należy pamiętać, że mixiny istnieją tylko w językach wielokrotnego dziedziczenia. Nie możesz zrobić miksu w Javie lub C #.
Zasadniczo mixin to samodzielny typ podstawowy, który zapewnia ograniczoną funkcjonalność i rezonans polimorficzny dla klasy potomnej. Jeśli myślisz w języku C #, pomyśl o interfejsie, którego nie musisz implementować, ponieważ jest już zaimplementowany; po prostu dziedziczysz po nim i korzystasz z jego funkcjonalności.
Mixiny mają zazwyczaj wąski zakres i nie mają być przedłużane.
[edytuj - dlaczego:]
Przypuszczam, że powinienem odpowiedzieć na pytanie dlaczego, skoro pytasz. Dużą zaletą jest to, że nie musisz robić tego sam od nowa. W języku C # największym miejscem, w którym mieszanka mogłaby skorzystać, może być wzór usuwania . Ilekroć implementujesz IDisposable, prawie zawsze chcesz postępować według tego samego wzorca, ale kończysz się pisaniem i ponownym pisaniem tego samego podstawowego kodu z niewielkimi zmianami. Gdyby istniała rozszerzalna mieszanka usuwania, możesz zaoszczędzić sobie dużo dodatkowego pisania.
[edytuj 2 - aby odpowiedzieć na inne pytania]
Tak. Różnica między mixinem a standardowym wielokrotnym dziedziczeniem jest tylko kwestią semantyki; klasa, która ma wielokrotne dziedziczenie, może wykorzystywać mixin jako część tego wielokrotnego dziedziczenia.
Celem mixin jest stworzenie typu, który można „wmieszać” do dowolnego innego typu poprzez dziedziczenie bez wpływu na typ dziedziczenia, a jednocześnie oferować 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, aby wymyślić przyzwoity przykład, który dostarczy tylko „ahah!” chwila dla ciebie. Ale spróbuję jeszcze raz. Będę używał przykładu, który został wymyślony - większość języków już udostępnia tę funkcję w taki czy inny sposób - ale mam nadzieję, że wyjaśni to, w jaki sposób należy tworzyć i wykorzystywać miksy. Tutaj idzie:
Załóżmy, że masz typ, który chcesz móc serializować do iz XML. Chcesz, aby typ zapewniał metodę „ToXML”, która zwraca ciąg zawierający fragment XML z wartościami danych typu, oraz „FromXML”, który pozwala typowi zrekonstruować wartości danych z fragmentu XML w ciągu. Ponownie, jest to wymyślony przykład, więc być może używasz strumienia plików lub klasy XML Writer z biblioteki wykonawczej twojego języka ... cokolwiek. Chodzi o to, że chcesz serializować swój obiekt do formatu XML i odzyskać nowy obiekt z formatu XML.
Innym ważnym punktem w tym przykładzie jest to, że chcesz to zrobić w sposób ogólny. Nie chcesz implementować metod „ToXML” i „FromXML” dla każdego typu, który chcesz serializować, potrzebujesz ogólnych sposobów zapewnienia, że Twój typ to zrobi i po prostu zadziała. Chcesz ponownie użyć kodu.
Jeśli Twój język to obsługuje, możesz utworzyć XmlSerializable, aby wykonać swoją pracę za Ciebie. Ten typ implementuje metody ToXML i FromXML. Korzystając z jakiegoś mechanizmu, który nie jest ważny w tym przykładzie, byłby w stanie zebrać wszystkie niezbędne dane z dowolnego typu, z którym jest zmieszany, w celu zbudowania fragmentu XML zwróconego przez ToXML i byłby równie zdolny do przywracania tych danych, gdy FromXML jest nazywa.
I to wszystko. Aby z niego skorzystać, musisz mieć dowolny typ, który musi być serializowany do XML dziedziczonego z XmlSerializable. Ilekroć trzeba było serializować lub deserializować tego typu, wystarczy wywołać ToXML lub FromXML. W rzeczywistości, ponieważ XmlSerializable jest pełnoprawnym typem i polimorficznym, możliwe jest zbudowanie serializatora dokumentów, który nie wie nic o twoim oryginalnym typie, akceptując tylko, powiedzmy, tablicę typów XmlSerializable.
Teraz wyobraź sobie, że wykorzystujesz ten scenariusz do innych celów, takich jak tworzenie miksu, który zapewnia, że każda klasa, która miksuje go w dzienniku, rejestruje każde wywołanie metody, lub miks, który zapewnia transakcyjność względem typu, który go miksuje. Lista może być długa.
Jeśli po prostu myślisz o mixinie jako małym typie podstawowym zaprojektowanym w celu dodania niewielkiej ilości funkcjonalności do typu bez wpływu na ten typ, to jesteś złoty.
Ufnie. :)
źródło
Ta odpowiedź ma na celu wyjaśnienie mixin przykładami , które:
samodzielny : krótki, bez potrzeby znajomości bibliotek, aby zrozumieć przykład.
w Pythonie , a nie w innych językach.
Zrozumiałe jest, że istniały przykłady z innych języków, takich jak Ruby, ponieważ termin jest znacznie bardziej powszechny w tych językach, ale jest to wątek w języku Python .
Rozważy również kontrowersyjne pytanie:
Definicje
Nie widziałem jeszcze cytatu z „autorytatywnego” źródła, w którym wyraźnie mówi się, co to jest mixin w Pythonie.
Widziałem 2 możliwe definicje mixinu (jeśli należy je uważać za różne od innych podobnych pojęć, takich jak abstrakcyjne klasy podstawowe), a ludzie nie do końca zgadzają się co do tego, która z nich jest poprawna.
Konsensus może być różny w różnych językach.
Definicja 1: brak wielokrotnego dziedziczenia
Mixin jest taką klasą, że niektóre metody tej klasy wykorzystują metodę, która nie jest zdefiniowana w klasie.
Dlatego klasa nie jest przeznaczona do tworzenia instancji, ale raczej służy jako klasa podstawowa. W przeciwnym razie instancja miałaby metody, których nie można wywołać bez zgłaszania wyjątku.
Ograniczeniem dodawanym przez niektóre źródła jest to, że klasa może nie zawierać danych, tylko metody, ale nie rozumiem, dlaczego jest to konieczne. W praktyce jednak wiele przydatnych miksów nie ma żadnych danych, a klasy podstawowe bez danych są prostsze w użyciu.
Klasycznym przykładem jest implementacja wszystkich operatorów porównania tylko
<=
i==
:Ten konkretny przykład można było osiągnąć za pomocą
functools.total_ordering()
dekoratora, ale tutaj gra miała na celu wynalezienie koła:Definicja 2: wielokrotne dziedziczenie
Mixin to wzorzec projektowy, w którym jakaś metoda klasy bazowej wykorzystuje metodę, której nie definiuje, i ta metoda ma być zaimplementowana przez inną klasę bazową , a nie przez pochodną jak w definicji 1.
Termin klasa mixin odnosi się do klas podstawowych, które mają być stosowane w tym wzorze projektowym (TODO tych, które stosują tę metodę, lub tych, które ją wdrażają?)
Nie jest łatwo zdecydować, czy dana klasa jest miksem, czy nie: metoda może być po prostu zaimplementowana w klasie pochodnej, w którym to przypadku wracamy do definicji 1. Musisz wziąć pod uwagę intencje autora.
Ten wzór jest interesujący, ponieważ możliwe jest ponowne połączenie funkcjonalności z różnymi wyborami klas podstawowych:
Autorytatywne wystąpienia Pythona
W oficjalnej dokumentacji dla kolekcji.abc w dokumentacji wyraźnie użyto terminu Metody mieszania .
Stwierdza, że jeśli klasa:
__next__
Iterator
wtedy klasa otrzymuje
__iter__
metodę miksowania za darmo.Dlatego przynajmniej w tym punkcie dokumentacji mixin nie wymaga wielokrotnego dziedziczenia i jest spójny z definicją 1.
Dokumentacja może oczywiście być sprzeczna w różnych punktach, a inne ważne biblioteki Pythona mogą używać innej definicji w swojej dokumentacji.
Ta strona używa również terminu
Set mixin
, który wyraźnie sugeruje, że klasy lubiąSet
iIterator
mogą być nazywane klasami Mixin.W innych językach
Ruby: Najwyraźniej nie wymaga wielokrotnego dziedziczenia dla mixin, jak wspomniano w głównych książkach, takich jak Programowanie Ruby i Język programowania Ruby
C ++: Metoda, która nie jest zaimplementowana, jest metodą czysto wirtualną.
Definicja 1 pokrywa się z definicją klasy abstrakcyjnej (klasy, która ma czysto wirtualną metodę). Nie można utworzyć tej klasy.
Definicja 2 jest możliwa w przypadku dziedziczenia wirtualnego: wielokrotne dziedziczenie z dwóch klas pochodnych
źródło
Myślę o nich jako o zdyscyplinowanym sposobie korzystania z wielokrotnego dziedziczenia - ponieważ ostatecznie mixin jest po prostu kolejną klasą python, która (może) przestrzega konwencji o klasach zwanych mixinami.
Rozumiem konwencje, które rządzą czymś, co nazwałbyś Mixinem, że Mixin:
object
(w Pythonie)W ten sposób ogranicza potencjalną złożoność wielokrotnego dziedziczenia i ułatwia śledzenie przepływu programu, ograniczając miejsce, w którym należy szukać (w porównaniu do pełnego wielokrotnego dziedziczenia). Są podobne do modułów ruby .
Jeśli chcę dodać zmienne instancji (z większą elastycznością, niż pozwala na to pojedyncze dziedziczenie), to zwykle wybieram kompozycję.
Powiedziawszy to, widziałem klasy o nazwie XYZMixin, które mają zmienne instancji.
źródło
Mixiny to koncepcja programowania, w której klasa zapewnia funkcjonalności, ale nie jest przeznaczona do tworzenia instancji. Głównym celem Mixins jest zapewnienie niezależnych funkcjonalności i najlepiej byłoby, gdyby same mixiny nie miały dziedziczenia z innymi mixinami, a także unikały stanu. W językach takich jak Ruby istnieje bezpośrednie wsparcie dla języków, ale dla Pythona nie. Można jednak użyć dziedziczenia wielu klas, aby wykonać funkcje dostarczone w języku Python.
Obejrzałem ten film http://www.youtube.com/watch?v=v_uKI2NOLEM, aby zrozumieć podstawy miksów. Dla początkującego bardzo przydatne jest zrozumienie podstaw mixin i ich działania oraz problemów, jakie możesz napotkać przy ich wdrażaniu.
Wikipedia jest wciąż najlepsza: http://en.wikipedia.org/wiki/Mixin
źródło
Mixin jest ograniczoną formą wielokrotnego dziedziczenia. W niektórych językach mechanizm dodawania mixinu do klasy jest nieco inny (pod względem składni) od dziedziczenia.
Szczególnie w kontekście Pythona, mixin jest klasą nadrzędną, która zapewnia funkcjonalność podklasom, ale nie jest przeznaczona do tworzenia instancji.
To, co może sprawić, że powiesz „to tylko wielokrotne dziedziczenie, a nie tak naprawdę mixin”, to fakt, że klasa, która mogłaby zostać pomylona z mixinem, może być faktycznie utworzona i użyta - tak więc jest to różnica semantyczna i bardzo realna.
Przykład wielokrotnego dziedziczenia
Ten przykład z dokumentacji to licznik zamówień:
To podklas zarówno
Counter
iOrderedDict
odcollections
modułu.Zarówno
Counter
iOrderedDict
są przeznaczone do wystąpienia i stosowane na własną rękę. Jednak poprzez podklasowanie ich obu, możemy mieć licznik, który jest uporządkowany i ponownie wykorzystuje kod w każdym obiekcie.Jest to skuteczny 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, poprawienie go bez opieki może spowodować błąd w podklasie.
Przykład mieszanki
Mixiny są zwykle promowane jako sposób na ponowne użycie kodu bez potencjalnych problemów z łączeniem, które mogłyby mieć wielokrotne dziedziczenie kooperatywne, takie jak licznik zleceń. Korzystając z miksów, korzystasz z funkcji, które nie są tak ściśle powiązane z danymi.
W przeciwieństwie do powyższego przykładu, mixin nie jest przeznaczony do samodzielnego stosowania. Zapewnia nową lub inną funkcjonalność.
Na przykład standardowa biblioteka ma kilka mixin w
socketserver
bibliotece .W takim przypadku metody mieszania zastępują metody w
UDPServer
definicji obiektu, aby umożliwić współbieżność.Metoda wydaje się być przesłonięte
process_request
i zapewnia również inną metodęprocess_request_thread
. Oto z kodu źródłowego :Wymyślony przykład
To jest mixin przeznaczony głównie do celów demonstracyjnych - większość obiektów ewoluuje poza użyteczność tego repr:
a użycie byłoby:
I użycie:
źródło
Myślę, że było tu kilka dobrych wyjaśnień, ale chciałem przedstawić inną perspektywę.
W Scali możesz tworzyć miksy, jak to tutaj opisano, ale bardzo interesujące jest to, że miksy są w rzeczywistości „połączone” w celu stworzenia nowego rodzaju klasy, z której można dziedziczyć. Zasadniczo nie dziedziczysz po wielu klasach / miksach, ale generujesz nowy rodzaj klasy ze wszystkimi właściwościami miksu do dziedziczenia. Ma to sens, ponieważ Scala jest oparty na JVM, w którym wielokrotne dziedziczenie nie jest obecnie obsługiwane (od Java 8). Nawiasem mówiąc, ten typ klasy mixin jest specjalnym typem zwanym Trait in Scala.
Jest to wskazane w sposobie definiowania klasy: klasa NewClass rozszerza FirstMixin o SecondMixin o ThirdMixin ...
Nie jestem pewien, czy interpreter CPython robi to samo (mixin-skład klasy), ale nie byłbym zaskoczony. Ponadto, wywodząc się ze środowiska C ++, nie nazwałbym ABC ani „interfejsem” równoważnym mixinowi - to podobna koncepcja, ale różni się w użyciu i implementacji.
źródło
Odradzałbym pomyłki w nowym kodzie Python, jeśli można znaleźć inne rozwiązanie (takie jak kompozycja zamiast dziedziczenia lub po prostu metody łatania małp w swoich klasach), które nie są niczym więcej wysiłek.
W klasach w starym stylu można użyć wtyczek jako sposobu na pobranie kilku metod z innej klasy. Ale w świecie w nowym stylu wszystko, nawet wtyczka, dziedziczy po
object
. Oznacza to, że każde użycie wielokrotnego dziedziczenia w naturalny sposób wprowadza problemy z MRO .Istnieją sposoby na sprawienie, aby wielodoliczkowe MRO działało w Pythonie, w szczególności funkcja super (), ale oznacza to, że musisz wykonać całą hierarchię klas za pomocą super () i znacznie trudniej jest zrozumieć przepływ kontroli.
źródło
Być może pomoże kilka przykładów.
Jeśli budujesz klasę i chcesz, aby działała jak słownik, możesz zdefiniować wszystkie
__ __
niezbędne metody. Ale to trochę boli. Alternatywnie możesz po prostu zdefiniować kilka i odziedziczyć (oprócz każdego innego dziedziczenia) zUserDict.DictMixin
(przeniesione docollections.DictMixin
w py3k). Spowoduje to automatyczne zdefiniowanie całej reszty interfejsu API słownika.Drugi przykład: zestaw narzędzi GUI wxPython umożliwia tworzenie kontrolek listy z wieloma kolumnami (np. Wyświetlanie pliku w Eksploratorze Windows). Domyślnie te listy są dość podstawowe. Możesz dodać dodatkowe funkcje, takie jak możliwość sortowania listy według konkretnej kolumny, klikając nagłówek kolumny, dziedzicząc z ListCtrl i dodając odpowiednie miksy.
źródło
Nie jest to przykład w języku Python, ale w języku programowania D termin
mixin
ten odnosi się do konstrukcji używanej w podobny sposób; dodając stos rzeczy do klasy.W D (który, nawiasem mówiąc, nie robi MI), robi się to poprzez wstawienie szablonu (pomyśl makrozkładne i bezpieczne makra, a będziesz blisko) do zakresu. Pozwala to na rozwinięcie pojedynczej linii kodu w klasie, strukturze, funkcji, module lub czymkolwiek innym do dowolnej liczby deklaracji.
źródło
OP wspomniał, że nigdy nie słyszał o mixinie w C ++, być może dlatego, że w C ++ są one nazywane Curiously Recurring Pattern Pattern (CRTP). Ponadto @Ciro Santilli wspomniał, że mixin jest implementowany za pomocą abstrakcyjnej klasy bazowej w C ++. Podczas gdy abstrakcyjna klasa bazowa może być użyta do implementacji mixin, jest to przesada, ponieważ funkcjonalność funkcji wirtualnej w czasie wykonywania można uzyskać za pomocą szablonu w czasie kompilacji bez narzutu związanego z wyszukiwaniem tabeli wirtualnej w czasie wykonywania.
Wzór CRTP jest szczegółowo opisany tutaj
Przekształciłem przykład Pythona w odpowiedzi @Ciro Santilli na C ++ przy użyciu klasy szablonów poniżej:
EDYCJA: Dodano chroniony konstruktor w ComparableMixin, dzięki czemu można go tylko dziedziczyć i nie tworzyć jego instancji. Zaktualizowano przykład, aby pokazać, jak chroniony konstruktor spowoduje błąd kompilacji, gdy zostanie utworzony obiekt ComparableMixin.
źródło
Może przykład z rubinu może pomóc:
Możesz dołączyć mixin
Comparable
i zdefiniować jedną funkcję"<=>(other)"
, mixin zapewnia wszystkie te funkcje:Robi to, wywołując
<=>(other)
i zwracając właściwy wynik."instance <=> other"
zwraca 0, jeśli oba obiekty są równe, mniej niż 0, jeśliinstance
jest większy,other
a więcej niż 0, jeśliother
jest większy.źródło
__lt__
jako podstawa zamiast__cmp__
, z których ta ostatnia jest faktycznie przestarzała i odradzana w użyciu. Wydaje mi się, że łatwiej jest używać tego mixinu zamiast dość skomplikowanych dekoratorów (część funools ) - chociaż ten może być w stanie bardziej dynamicznie reagować na to, jakie porównania są zapewnione ...mixin daje możliwość dodania funkcjonalności w klasie, tzn. możesz wchodzić w interakcje z metodami zdefiniowanymi w module, włączając moduł do pożądanej klasy. Chociaż ruby nie obsługuje wielokrotnego dziedziczenia, ale zapewnia mixin jako alternatywę do osiągnięcia tego.
oto przykład, który wyjaśnia, w jaki sposób osiąga się wielokrotne dziedziczenie za pomocą mixin.
źródło
Właśnie użyłem miksu Pythona do zaimplementowania testowania jednostkowego milterów Pythona. Zwykle milter rozmawia z MTA, co utrudnia testy jednostkowe. Mixin testowy zastępuje metody komunikujące się z MTA i zamiast tego tworzy symulowane środowisko oparte na przypadkach testowych.
Więc bierzesz niezmodyfikowaną aplikację milter, taką jak spfmilter i mixin TestBase, taką jak ta:
Następnie użyj TestMilter w przypadkach testowych aplikacji milter:
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
źródło
Myślę, że poprzednie odpowiedzi bardzo dobrze określały, czym są MixIns . Jednak w celu lepszego ich zrozumienia przydatne może być porównanie MixIns z klasami abstrakcyjnymi i interfejsami z perspektywy kodu / implementacji:
1. Klasa abstrakcyjna
Klasa, która musi zawierać jedną lub więcej metod abstrakcyjnych
Klasa abstrakcyjna może zawierać metody stanowe (zmienne instancji) i metody nieabstrakcyjne
2. Interfejs
3. MixIns
Na przykład w Pythonie są to tylko konwencje, ponieważ wszystkie powyższe są zdefiniowane jako
class
es. Jednak wspólną cechą klas abstrakcyjnych, interfejsów i MixIns jest to, że nie powinny one istnieć same, tzn. Nie powinny być tworzone.źródło
Przeczytałem, że masz tło ac #. Tak więc dobrym punktem wyjścia może być implementacja mixin dla platformy .NET.
Możesz sprawdzić projekt codeplex na stronie http://remix.codeplex.com/
Obejrzyj link Sympozjum lang.net, aby uzyskać przegląd. Dokumentacja na stronie codeplex wymaga jeszcze więcej.
w odniesieniu do Stefana
źródło