Was sind (konkrete) Anwendungsfälle für Metaklassen?
Ich habe einen Freund, der gerne Metaklassen, und regelmäßig bietet Ihnen eine Lösung.
Ich bin der Meinung, dass man fast nie verwenden müssen Metaklassen. Warum? weil ich denke, wenn Sie etwas wie, dass die Klasse, die sollten Sie vielleicht machen es zu einem Objekt. Und ein kleines redesign/Refactoring ist in Ordnung.
Nutzen zu können Metaklassen verursacht hat viele Menschen in eine Menge von Orten, die die Verwendung von Klassen als eine Art zweite rate-Objekt, das scheint nur katastrophal für mich. Ist die Programmierung ersetzt werden durch meta-Programmierung? Der Zusatz class decorators hat leider schafften es sogar noch akzeptabel.
Also bitte, ich bin verzweifelt, zu wissen, Ihren gültigen (Beton) Anwendungsfall für Metaklassen in Python. Oder erleuchtet zu werden, warum mutierend Klassen besser ist als mutierend Objekte, manchmal in.
Werde ich beginnen:
Manchmal, wenn ein Fremdanbieter-
Bibliothek es ist nützlich, zu können
mutieren Sie die Klasse in einer bestimmten Weise.
(Dies ist der einzige Fall, an den ich denken kann, und es ist nicht Beton)
InformationsquelleAutor der Frage Ali Afshar | 2008-12-24
Du musst angemeldet sein, um einen Kommentar abzugeben.
Habe ich eine Klasse, mit der nicht-interaktiven Plotten, als ein frontend für Matplotlib. Aber gelegentlich will man machen interaktive Plotten. Mit nur ein paar Funktionen, die ich fand, dass ich war in der Lage, erhöhen Sie die Zahl, zählen, rufen Sie zeichnen manuell, etc, aber ich brauchte, um diese vor und nach jedem Plotten aufrufen. So erstellen Sie sowohl eine interaktive Plotten wrapper und eine offscreen-Plotten-wrapper, ich fand es effizienter ist, dies zu tun über Metaklassen, wickeln der geeigneten Methoden, als etwas zu tun wie:
Diese Methode nicht Schritt halten mit API-änderungen und so weiter, aber eine, die durchläuft die Attribute der Klasse in
__init__
vor der re-Einstellung der Attribute der Klasse ist effizienter und hält die Dinge auf dem neuesten Stand:Natürlich, es gibt bestimmt bessere Wege dies zu tun, aber ich habe festgestellt, das, um wirksam zu sein. Natürlich könnte man auch im
__new__
oder__init__
war, aber das war die Lösung, die ich gefunden, die meisten einfach.InformationsquelleAutor der Antwort Matt
Ich wurde gebeten, die gleiche Frage vor kurzem, und kam mit mehreren Antworten. Ich hoffe es ist OK diesen thread wieder zu beleben, als wollte ich näher auf einige der Anwendungsfälle erwähnt, und fügen Sie ein paar neue.
Meisten Metaklassen ich habe gesehen, eines von zwei Dingen tun:
Registrierung (eine Klasse hinzufügen, um eine Daten-Struktur):
Wann immer Sie eine Unterklasse
Model
Ihre Klasse registriert ist, in dermodels
Wörterbuch:Dies kann auch durchgeführt werden mit der Klasse Dekorateure:
Oder mit einer expliziten Registrierung Funktion:
Eigentlich, das ist so ziemlich das gleiche: Sie erwähnen Klasse Dekorateure ungünstig, aber es ist wirklich nichts anderes als syntaktischer Zucker für ein Funktions-Aufruf in einer Klasse, so gibt es keine Magie über es.
Eh, der Vorteil von Metaklassen in diesem Fall ist die Vererbung, wie Sie arbeiten, für die keine Unterklassen, während die anderen Lösungen funktionieren nur für Unterklassen explizit eingerichtet bzw. registriert werden.
Refactoring (ändern von Klassen-Attribute oder neue hinzufügen):
Wann immer Sie eine Unterklasse
Model
und definieren einigeField
Attribute, injiziert werden Sie mit Ihrem Namen (für mehr informative Fehlermeldungen, zum Beispiel), und gruppiert in einem_fields
Wörterbuch (für die einfache iteration, suchen, ohne durch alle class-Attribute und-alle Ihre Basisklassen Attribute jedes mal):Wieder, diese kann getan werden (ohne Vererbung) mit einer Klasse decorator:
Oder explizit:
Obwohl das im Widerspruch zu Ihrem eintreten für lesbar und wartbar non-meta-Programmierung, dies ist viel mehr umständlich, redundant und fehleranfällig:
Haben als die gemeinsamen und konkreten Anwendungsfälle, die nur in Fällen, wo Sie absolut verwenden MÜSSEN Metaklassen sind, wenn Sie möchten, ändern Sie den Namen der Klasse oder eine Liste von Basisklassen, denn einmal definiert, werden diese Parameter sind fest in der Klasse, und kein Dekorateur oder Funktion kann unbake.
Dies kann hilfreich sein, den Rahmen für die Erteilung von Warnungen, wenn Klassen mit ähnlichen Namen oder unvollständige Vererbung Bäume sind definiert, aber ich kann nicht denken, ein Grund, neben trolling tatsächlich verändern sich diese Werte. Vielleicht David Beazley können.
Sowieso in Python 3, Metaklassen haben auch die
__prepare__
- Methode, die können Sie bewerten den Klasse Körper in einem mapping andere als eindict
und unterstützen so bestellt Attribute, überladene Attribute und andere böse cool stuff:Könnte man argumentieren bestellt Parametern erreicht werden kann, mit der Schöpfung Zähler, und überladen kann simuliert werden mit default-Argumenten:
Abgesehen davon, dass viel mehr hässlich, es ist auch weniger flexibel: was ist, wenn Sie bestellten literal Attribute, wie Ganzzahlen und strings? Was ist, wenn
None
ist ein Gültiger Wert fürx
?Hier ist eine kreative Art zu lösen das erste problem:
Und hier ist eine kreative Art und Weise zu lösen, die zweite:
Aber das ist viel, VIEL voodoo-er als eine einfache Metaklasse (vor allem das erste, das wirklich schmilzt dein Gehirn). Mein Punkt ist, schauen Sie auf Metaklassen, Fremd-und counter-intuitive, aber Sie können auch sehen Sie als den nächsten Schritt der evolution in den Programmiersprachen: Sie müssen nur passen Sie Ihre Denkweise. Nach allem, könnten Sie wahrscheinlich alles tun, was in C, einschließlich der Definition eines struct mit funktionspointern und übergeben Sie als erstes argument für seine Funktionen. Eine person zu sehen, C++ für die erste Zeit könnte sagen, "was ist das für Magie? Warum ist der compiler implizit übergeben
this
zu Methoden, aber nicht regelmäßig und statische Funktionen? Es ist besser, explizit und ausführlich über Ihre Argumente". Aber dann, Objekt-orientierte Programmierung ist viel leistungsfähiger, wenn Sie es bekommen; und so ist diese, äh... quasi-Aspekt-orientierte Programmierung, denke ich. Und wenn Sie verstehen, metaclasses, eigentlich sind Sie sehr einfach, also warum nicht verwenden Sie, wenn bequem?Und schließlich Metaklassen sind toll, und die Programmierung sollte Spaß machen. Mit standard-Programmier-Konstrukte und design-Muster, ist die ganze Zeit langweilig und langweilig, und behindert Ihre Phantasie. Ein wenig Leben! Hier ist ein metametaclass, nur für Sie.
InformationsquelleAutor der Antwort Dan Gittik
Zweck der Metaklassen ist nicht zu ersetzen der Klasse/Objekt-Unterscheidung mit metaclass/Klasse - es ist zu ändern, das Verhalten von Klassen-Definitionen (und damit auch deren Instanzen) in gewisser Weise. Effektiv, es zu ändern, das Verhalten der class-Anweisung in einer Weise, die möglicherweise mehr nützlich für Ihre spezifischen Domäne als der Standard. Die Dinge, die ich verwendet haben Sie sind:
Tracking-Unterklassen, die in der Regel auf register-Handler. Das ist praktisch, wenn mit einem plugin, Stil setup, wo Sie wollen, um einen handler registrieren, der für eine bestimmte Sache einfach, indem bilden von Unterklassen und die Einrichtung ein paar Attribute der Klasse. zB. angenommen, Sie schreiben eine Prozedur für verschiedene Musik-Formate, wo jede Klasse implementiert geeignete Methoden (Spiele /get-tags etc) für seinen Typ. Hinzufügen eines handlers für einen neuen geben wird:
Die Metaklasse, dann hält ein Wörterbuch der
{'.mp3' : MP3File, ... }
etc, und konstruiert ein Objekt des entsprechenden Typs, wenn Sie request-handler durch eine factory-Funktion.Veränderung von Verhaltensweisen. Sie kann angehängt werden soll, eine Besondere Bedeutung zu, die bestimmte Eigenschaften, resultierend in veränderten Verhalten, wenn Sie vorhanden sind. Zum Beispiel, möchten Sie vielleicht zu suchen für die Methoden mit den Namen
_get_foo
und_set_foo
transparent und konvertieren Sie Sie dann auf Eigenschaften. Wie ein real-world Beispiel, hier ein Rezept, das ich schrieb, mehr zu geben, C-wie die struct-Definitionen. Die Metaklasse ist die Umrechnung der deklarierten Elemente in einer struct format-string, Umgang mit Vererbung etc, und produzieren eine Klasse in der Lage den Umgang mit ihm.Für andere Reale Beispiele, werfen Sie einen Blick auf verschiedene ORMs, wie sqlalchemy ist ORM oder sqlobject. Nochmals, der Zweck ist, zu interpretieren, Definitionen (hier SQL-Spalte-Definitionen) mit einer bestimmten Bedeutung.
InformationsquelleAutor der Antwort Brian
Beginnen wir mit Tim Peters classic Zitat:
Gesagt, dass ich (regelmäßig) laufen über echte Verwendungen von Metaklassen. Die eine, die den Sinn kommt, ist in Django, wo Sie alle Ihre Modelle Erben von Modellen.Modell. Modelle.Modell trägt wiederum einige ernsthafte Magie, um wickeln Sie Ihre DB-Modelle mit Djangos ORM Güte. Die Magie geschieht durch Metaklassen. Es erstellt alle Arten von exception-Klassen, manager-Klassen, etc. etc.
Sehen django/db/models/base.py, class ModelBase() für den Anfang der Geschichte.
InformationsquelleAutor der Antwort Peter Rowell
Metaklassen kann nützlich sein, für den Bau von domänenspezifischen Sprachen in Python. Konkrete Beispiele Django, SQLObject 's deklarative syntax von Datenbank-schemata.
Einem einfachen Beispiel aus Eine Konservative Metaklasse von Ian Bicking:
Einige andere Techniken: Zutaten für den Aufbau einer DSL in Python (pdf).
Bearbeiten (von Ali): Ein Beispiel, das mit den Sammlungen und den Instanzen, ist das, was ich bevorzugen würde. Die wichtige Tatsache ist, die Instanzen, die Ihnen mehr macht, und beseitigen Grund für die Verwendung von Metaklassen. Weiter erwähnenswert ist, dass dein Beispiel nutzt eine Mischung von Klassen und Instanzen, das ist doch sicherlich ein Hinweis darauf, dass Sie nicht einfach tun es alle mit Metaklassen. Und schafft eine wirklich non-uniform Weg, es zu tun.
Es ist nicht perfekt, aber es gibt schon fast keine Magie, keine Notwendigkeit für Metaklassen, und verbesserte Homogenität.
InformationsquelleAutor der Antwort jfs
Dachte ich das gleiche gerade gestern und ganz Zustimmen. Die Komplikationen, die in dem code verursacht, der durch versuche zu machen, mehr deklarative Regel machen die codebase, die schwieriger zu pflegen, schwieriger zu Lesen und weniger pythonic meiner Meinung nach.
Es auch erfordert in der Regel eine Menge kopieren.copy()ing (Pflege, Vererbung und kopieren von Klasse zu Instanz) und bedeutet, dass Sie schauen müssen, in viele Orte, um zu sehen, was Los ist, (immer auf der Suche von metaclass-up), die sich gegen die python Getreide auch.
Ich habe Kommissionierung durch formencode und sqlalchemy-code zu sehen, wenn eine solche deklarativen Stil, der es Wert war und seine eindeutig nicht. Ein solcher Stil sollte überlassen werden, um Deskriptoren (wie Eigentum und Methoden) und unveränderliche Daten.
Ruby hat eine bessere Unterstützung für solche deklarative Stile und ich bin froh, dass die core-Sprache python ist nicht nach unten dieser Strecke.
Ich sehen kann für das Debuggen verwenden, fügen Sie eine Metaklasse alle Ihre Basisklassen, um umfangreichere Infos.
Ich sehe auch, dass Ihre Verwendung nur in (sehr) großen Projekten, um loszuwerden, einige boilerplate code (aber auf den Verlust von Klarheit). sqlalchemy für Beispiel verwenden Sie Sie an anderer Stelle, hinzufügen einer bestimmten benutzerdefinierten Methode für alle Unterklassen basierend auf einem Attribut mit dem Wert in Ihrer Klasse definition
e.g ein Spielzeug Beispiel
hätte eine Metaklasse, die generiert einer Methode in dieser Klasse mit besonderen Eigenschaften auf Basis von "hello" (sagen, eine Methode, die Hinzugefügt "Hallo" an das Ende der Zeichenkette). Es könnte gut für die Wartbarkeit sicherstellen, dass Sie nicht haben, um zu schreiben, eine Methode in jeder Unterklasse, die Sie machen, anstatt alles, was Sie zu definieren, ist method_maker_value.
Die Notwendigkeit dieser ist so selten, wenn und nur spart ein wenig Tipparbeit, dass es nicht wirklich eine überlegung Wert, es sei denn, Sie haben eine ausreichend große Basis zu nutzen.
InformationsquelleAutor der Antwort David Raznick
Einer angemessenen Muster der Metaklasse zu verwenden ist, etwas zu tun, als eine Klasse definiert ist, anstatt immer wieder, wenn die gleiche Klasse instanziiert wird.
Wenn mehrere Klassen denselben ein spezielles Verhalten, wiederholen
__metaclass__=X
ist offensichtlich besser als die Wiederholung der spezielle Zweck-code und/oder die Einführung von ad-hoc-gemeinsame Oberklassen.Aber auch mit nur einer speziellen Klasse und nicht vorhersehbaren Erweiterung
__new__
und__init__
einer Metaklasse sind ein sauberer Weg zum initialisieren von Klassenvariablen oder andere Globale Daten als Vermischung speziellen code und normalendef
undclass
Aussagen in der definition der Klasse Körper.InformationsquelleAutor der Antwort user412090
Du nie absolut müssen Verwendung einer Metaklasse, da kann man immer konstruieren Sie eine Klasse, die tut, was Sie wollen mit der Vererbung oder aggregation der Klasse, die Sie ändern möchten.
Das heißt, es kann sehr nützlich sein in Smalltalk und Ruby zu ändern, können Sie eine vorhandene Klasse, aber Python nicht mag, das zu tun, direkt.
Gibt es eine hervorragende DeveloperWorks Artikel auf metaclassing in Python, die helfen könnten. Die Wikipedia-Artikel ist auch ziemlich gut.
InformationsquelleAutor der Antwort Charlie Martin
Die einzige Zeit, die ich verwendet Metaklassen in Python war beim schreiben ein wrapper für die Flickr-API.
Mein Ziel war, zu kratzen der flickr-api-Seite und dynamisch generieren eine komplette Klassenhierarchie zu ermöglichen API-Zugriff mit Python-Objekte:
So, in diesem Beispiel, weil ich generiert die gesamte Python-Flickr-API von der website, ich weiß wirklich nicht, die Klassen-Definitionen zur Laufzeit. Lage, dynamisch zu generieren Typen, die sehr nützlich war.
InformationsquelleAutor der Antwort Triptych
Metaklassen sind nicht zu ersetzen-Programmierung! Sie sind nur ein trick, das zu automatisieren oder machen Sie mehr elegant einige Aufgaben. Ein gutes Beispiel HIERFÜR ist Pygments syntax-highlighting-Bibliothek. Es hat eine Klasse namens
RegexLexer
dem der Benutzer festgelegt werden, sind das sogenannte Lexing Regeln wie reguläre Ausdrücke in einer Klasse. Eine Metaklasse ist, können Sie die Definitionen in eine sinnvolle parser.Sind Sie wie Salz; es ist einfach zu viel.
InformationsquelleAutor der Antwort Benjamin Peterson
Die Art, wie ich verwendet Metaklassen wurde um einige Attribute zu den Klassen. Nehmen Sie zum Beispiel:
wird die Namen Attribut für jede Klasse, die die Metaklasse festgelegt Punkt zu NameClass.
InformationsquelleAutor der Antwort hyperboreean
Einige GUI-Bibliotheken haben Probleme, wenn mehrere threads versuchen, mit Ihnen zu interagieren.
tkinter
ist ein Beispiel dafür; und zwar kann man explizit behandelt das problem mit events und Warteschlangen, kann es viel einfacher zu verwenden der Bibliothek in einer Weise ignoriert, dass das problem insgesamt. Siehe -- die Magie der metaclasses.Können dynamisch umschreiben eine ganze Bibliothek nahtlos, so dass es funktioniert wie erwartet, in einer Multithread-Anwendung kann sehr hilfreich sein in einigen Fällen. Die safetkinter - Modul, das mit Hilfe einer Metaklasse bereitgestellt durch die threadbox Modul -- Veranstaltungen und Warteschlangen nicht notwendig.
Einem ordentlichen Aspekt der
threadbox
ist, dass es egal ist welche Klasse es-Klone. Es bietet ein Beispiel dafür, wie alle base-Klassen berührt werden können, durch eine Metaklasse, wenn nötig. Ein weiterer Vorteil ist, dass kommt mit Metaklassen ist, dass Sie Erben von den Klassen als gut. Programme, die selbst schreiben-warum nicht?InformationsquelleAutor der Antwort Noctis Skytower
Die einzige legitime use-case, der eine Metaklasse ist, um andere neugierige Entwickler von berühren deinen code. Einmal eine neugierige Entwickler masters Metaklassen und beginnt stochern mit Ihnen, werfen Sie in einer anderen Ebene oder zwei, um zu halten Sie aus. Wenn das nicht funktioniert, starten Sie mit
type.__new__
oder vielleicht ein Schema mit einer rekursiven metaclass.(geschrieben mit einem Augenzwinkern, aber ich habe gesehen, diese Art der Verschleierung gemacht. Django ist ein perfektes Beispiel)
InformationsquelleAutor der Antwort Mike A
Dies ist eine geringfügige, aber... eine Sache, die ich gefunden habe Metaklassen nützlich ist um eine Funktion aufzurufen, wenn eine Unterklasse erstellt wird. Ich kodifiziert diese in eine Metaklasse, die sieht für ein
__initsubclass__
Attribut: immer, wenn eine Unterklasse erstellt wird, werden alle übergeordneten Klassen, die definieren, dass die Methode aufgerufen wird, mit__initsubclass__(cls, subcls)
. Dies ermöglicht die Erstellung einer übergeordneten Klasse, die registriert dann alle Unterklassen mit einigen globalen Registrierung läuft invariante prüft auf Unterklassen, wenn Sie definiert sind, führen late-binding-Operationen, usw... alles ohne manuell aufrufen von Funktionen oder zum erstellen von benutzerdefinierten Metaklassen, die Sie durchführen, jede dieser einzelnen Aufgaben.Wohlgemerkt, ich habe langsam kommen, um zu erkennen, das implizite magicalness dieses Verhalten ist eher unerwünscht, da es zu unerwarteten, wenn man bei der definition einer Klasse aus dem Zusammenhang gerissen... und so habe ich verschoben, Weg von der Nutzung, die Lösung für etwas ernstes neben initialisieren eines
__super
Attribut für jede Klasse und Instanz.InformationsquelleAutor der Antwort Eli Collins
Ich hatte vor kurzem die Verwendung einer Metaklasse zu helfen deklarativ definieren SQLAlchemy Modell um eine Datenbank-Tabelle gefüllt mit US-Census-Daten von http://census.ire.org/data/bulkdata.html
IRE bietet Datenbank-Schalen für die Daten der Volkszählung von Tabellen, das erstellen von Ganzzahl-Spalten, die nach einer Namenskonvention, die vom Census Bureau der p012015, p012016, p012017, etc.
Wollte ich a) in der Lage sein, um Zugriff auf diese Säulen mit einem
model_instance.p012017
syntax, b) ziemlich explizit, was ich Tat, und c) nicht explizit definieren, die Dutzende von Bereichen auf das Modell, so dass ich untergeordnet SQLAlchemy istDeclarativeMeta
zum Durchlaufen einer Reihe von Spalten und automatisch die Erstellung von Modell-Felder der entsprechenden Spalten:Ich könnte dann mit dieser Metaklasse für mein Modell die definition und den Zugriff auf die automatisch aufgelistet Felder auf das Modell:
InformationsquelleAutor der Antwort Geoffrey Hing
Scheint es eine legitime Nutzung beschrieben hier - Rewriting Python Docstrings mit einer Metaklasse.
InformationsquelleAutor der Antwort mistermarko
Musste ich Sie einmal für eine Binär-parser, um es einfacher zu verwenden. Definieren Sie eine Klasse Nachricht mit den Attributen der Felder, die auf den Draht.
Sie musste bestellt werden, wie Sie deklariert wurden, die zur Konstruktion der endgültigen wire-format aus. Sie können tun, dass mit Metaklassen, wenn Sie eine geordnete namespace dict. In der Tat, seine in der Beispiele für Metaklassen:
https://docs.python.org/3/reference/datamodel.html#metaclass-example
Aber im Allgemeinen: Sehr sorgfältig auswerten, wenn Sie wirklich, wirklich brauchen, die zusätzliche Komplexität der metaclasses.
InformationsquelleAutor der Antwort GeeF