1371 Stimmen

Was ist ein Mixin und warum ist es nützlich?

En Programmierung von Python erwähnt Mark Lutz den Begriff mixin . Ich komme aus einem C/C++/C#-Hintergrund und habe den Begriff noch nie gehört. Was ist ein Mixin?

Lesen zwischen den Zeilen von dieses Beispiel (die ich verlinkt habe, weil sie recht lang ist), nehme ich an, dass es sich um einen Fall von Mehrfachvererbung handelt, um eine Klasse zu erweitern, im Gegensatz zur richtigen Unterklassifizierung. Ist das richtig?

Warum sollte ich das tun, anstatt die neue Funktionalität in eine Unterklasse aufzunehmen? Und warum wäre ein Mixin-/Mehrfachvererbungsansatz besser als die Verwendung von Komposition?

Was trennt ein Mixin von Mehrfachvererbung? Ist es nur eine Frage der Semantik?

44voto

Was trennt ein Mixin von Mehrfachvererbung? Ist es nur eine Frage der Semantik?

Ein Mixin ist eine begrenzte Form der Mehrfachvererbung. In einigen Sprachen unterscheidet sich der Mechanismus zum Hinzufügen eines Mixins zu einer Klasse geringfügig (in Bezug auf die Syntax) von dem der Vererbung.

Im Kontext von Python ist ein Mixin eine übergeordnete Klasse, die Funktionen für Unterklassen bereitstellt, aber selbst nicht instanziiert werden soll.

Was Sie dazu veranlassen könnte zu sagen, "das ist nur Mehrfachvererbung, nicht wirklich ein Mixin", ist, wenn die Klasse, die mit einem Mixin verwechselt werden könnte, tatsächlich instanziiert und verwendet werden kann - es ist also tatsächlich ein semantischer und sehr realer Unterschied.

Beispiel für Mehrfachvererbung

Dieses Beispiel, aus der Dokumentation ist ein 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),)

Sie ist eine Unterklasse sowohl der Counter und die OrderedDict del collections Modul.

Les deux Counter y OrderedDict sind dazu bestimmt, instanziiert und eigenständig verwendet zu werden. Indem wir sie jedoch beide unterklassifizieren, können wir einen Zähler haben, der geordnet ist und den Code in jedem Objekt wiederverwendet.

Dies ist eine gute Möglichkeit, Code wiederzuverwenden, kann aber auch problematisch sein. Wenn sich herausstellt, dass eines der Objekte einen Fehler enthält, kann die unvorsichtige Behebung dieses Fehlers einen Fehler in der Unterklasse verursachen.

Beispiel für ein Mixin

Mixins werden in der Regel als Mittel zur Wiederverwendung von Code ohne potenzielle Kopplungsprobleme beworben, die bei kooperativer Mehrfachvererbung, wie dem OrderedCounter, auftreten können. Wenn Sie Mixins verwenden, verwenden Sie Funktionen, die nicht so eng an die Daten gekoppelt sind.

Anders als im obigen Beispiel ist ein Mixin nicht dazu gedacht, allein verwendet zu werden. Es bietet neue oder andere Funktionen.

Die Standardbibliothek hat zum Beispiel eine Reihe von Mixins in der socketserver Bibliothek .

Von jedem Servertyp können Forking- und Threading-Versionen erstellt werden mithilfe dieser Mix-In-Klassen erstellt werden. Zum Beispiel wird ThreadingUDPServer wie folgt erstellt:

class ThreadingUDPServer(ThreadingMixIn, UDPServer):
    pass

Die Mix-in-Klasse steht an erster Stelle, da sie über UDPServer definiert ist. Das Setzen der verschiedenen Attribute ändert auch das Verhalten der des zugrunde liegenden Servermechanismus.

In diesem Fall überschreiben die Mixin-Methoden die Methoden in der UDPServer Objektdefinition, um Gleichzeitigkeit zu ermöglichen.

Die überschriebene Methode scheint zu sein process_request und bietet auch eine andere Methode, process_request_thread . Hier ist es von der Quellcode :

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

Ein erfundenes Beispiel

Dies ist ein Mixin, das hauptsächlich zu Demonstrationszwecken dient - die meisten Objekte werden sich über die Nützlichkeit dieser Repräsentation hinaus entwickeln:

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

und Nutzung sein:

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

Und Verwendung:

>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)

34voto

lakshmen Punkte 27002

Mixins sind ein Konzept in der Programmierung, bei dem die Klasse Funktionalitäten bereitstellt, aber nicht für die Instanziierung verwendet werden soll. Der Hauptzweck von Mixins ist die Bereitstellung von Funktionen, die eigenständig sind, und es wäre am besten, wenn die Mixins selbst keine Vererbung mit anderen Mixins haben und auch einen Zustand vermeiden. In Sprachen wie Ruby gibt es eine direkte Sprachunterstützung, in Python jedoch nicht. Sie könnten jedoch die in Python bereitgestellten Funktionen durch Vererbung mehrerer Klassen ausführen.

Ich habe dieses Video gesehen http://www.youtube.com/watch?v=v_uKI2NOLEM um die Grundlagen von Mixins zu verstehen. Für einen Anfänger ist es sehr nützlich, die Grundlagen von Mixins zu verstehen und zu wissen, wie sie funktionieren und welche Probleme bei ihrer Implementierung auftreten können.

Wikipedia ist immer noch das Beste: http://en.wikipedia.org/wiki/Mixin

20voto

Maggyero Punkte 4419

Das Konzept stammt von Steve's Eiscreme , einem 1973 von Steve Herrell in Somerville, Massachusetts, gegründeten Eiscafé, wo das Mix-Ins (Bonbons, Kuchen usw.) wurden in das Basiseis gemischt Geschmäcker (Vanille, Schokolade, etc.).

Inspiriert von Steve's Ice Cream, haben die Entwickler des Lisp-Objektsystems Geschmäcker wurde das Konzept zum ersten Mal in eine Programmiersprache aufgenommen, und zwar mit kleinen Hilfsklassen, die zur Verbesserung anderer Klassen entwickelt wurden und als Mix-Ins und große eigenständige Klassen, bekannt als Geschmäcker .

Der Grundgedanke ist also, dass ein Einmischen ist eine wiederverwendbare Verlängerung ("wiederverwendbar" im Gegensatz zu "exklusiv"; "Erweiterung" im Gegensatz zu "Basis").

Diese Definition ist orthogonal zu den Konzepten der Einfach- oder Mehrfachvererbung und der abstrakten oder konkreten Klasse. Mix-in-Klassen können für Einfach- oder Mehrfachvererbung verwendet werden, und Mix-in-Klassen haben unvollständige Schnittstellen, während abstrakte Klassen unvollständige Implementierungen und konkrete Klassen vollständige Implementierungen haben.

Mix-In-Klassennamen werden üblicherweise mit dem Zusatz '-MixIn', '-able' oder '-ible' versehen, um ihre Natur zu betonen, wie in der Python-Standardbibliothek mit dem ThreadingMixIn y ForkingMixIn Klassen des socketserver und das Modul Hashable , Iterable , Callable , Awaitable , AsyncIterable y Reversible Klassen des collections.abc Modul.

Beispiel für eine Mix-in-Klasse, die die in Python eingebaute Klasse list y dict Klassen mit Protokollierungsfunktion:

import logging

class LoggingMixIn:
    def __setitem__(self, key, value):
        logging.info('Setting %r to %r', key, value)
        super().__setitem__(key, value)
    def __delitem__(self, key):
        logging.info('Deleting %r', key)
        super().__delitem__(key)

class LoggingList(LoggingMixIn, list):
    pass

class LoggingDict(LoggingMixIn, dict):
    pass

>>> logging.basicConfig(level=logging.INFO)
>>> l = LoggingList([False])
>>> d = LoggingDict({'a': False})
>>> l[0] = True
INFO:root:Setting 0 to True
>>> d['a'] = True
INFO:root:Setting 'a' to True
>>> del l[0]
INFO:root:Deleting 0
>>> del d['a']
INFO:root:Deleting 'a'

13voto

SilentDirge Punkte 807

Ich denke, dass hier einige gute Erklärungen gegeben wurden, aber ich wollte eine andere Perspektive einbringen.

In Scala können Sie Mixins verwenden, wie hier beschrieben, aber was sehr interessant ist, ist, dass die Mixins tatsächlich miteinander "verschmolzen" werden, um eine neue Art von Klasse zu schaffen, von der sie erben. Im Wesentlichen erben Sie nicht von mehreren Klassen/Mixins, sondern erzeugen eine neue Art von Klasse mit allen Eigenschaften des Mixins, von dem Sie erben. Dies ist sinnvoll, da Scala auf der JVM basiert, wo Mehrfachvererbung derzeit nicht unterstützt wird (ab Java 8). Dieser Mixin-Klassentyp ist übrigens ein spezieller Typ, der in Scala Trait genannt wird.

Es wird in der Art und Weise angedeutet, wie class NewClass extends FirstMixin with SecondMixin with ThirdMixin ...

Ich bin mir nicht sicher, ob der CPython-Interpreter dasselbe tut (mixin class-composition), aber ich wäre nicht überrascht. Da ich aus einem C++-Hintergrund komme, würde ich ein ABC oder eine "Schnittstelle" nicht als Äquivalent zu einem Mixin bezeichnen - es handelt sich um ein ähnliches Konzept, das sich jedoch in der Verwendung und Implementierung unterscheidet.

10voto

John Fouhy Punkte 39035

Vielleicht helfen ein paar Beispiele.

Wenn Sie eine Klasse erstellen, die sich wie ein Wörterbuch verhalten soll, können Sie alle verschiedenen __ __ Methoden erforderlich. Aber das ist ein bisschen mühsam. Alternativ können Sie nur einige wenige definieren und (zusätzlich zu allen anderen Vererbungen) vererben von UserDict.DictMixin (verschoben nach collections.DictMixin in py3k). Dies hat den Effekt, dass der ganze Rest der Wörterbuch-API automatisch definiert wird.

Ein zweites Beispiel: Mit dem GUI-Toolkit wxPython können Sie Listen mit mehreren Spalten erstellen (z. B. die Dateianzeige im Windows Explorer). Standardmäßig sind diese Listen recht einfach gehalten. Sie können zusätzliche Funktionalität hinzufügen, wie z. B. die Möglichkeit, die Liste nach einer bestimmten Spalte zu sortieren, indem Sie auf die Spaltenüberschrift klicken, indem Sie von ListCtrl erben und entsprechende Mixins hinzufügen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X