Was ist eine Metaklasse in Python?

Was sind Metaklassen? Wofür verwenden Sie sie?

14 Solutions collect form web for “Was ist eine Metaklasse in Python?”

Eine Metaklasse ist die Klasse einer Klasse. Wie eine Klasse definiert, wie sich eine Instanz der Klasse verhält, definiert eine Metaklasse, wie sich eine Klasse verhält. Eine Klasse ist eine Instanz einer Metaklasse.

Metaclass Diagramm

Während in Python können Sie beliebige Callables für Metaclasses (wie Jerub zeigt), die nützlicher Ansatz ist eigentlich, um es eine tatsächliche Klasse selbst. type ist die übliche Metaklasse in Python. Für den Fall, dass Sie sich fragen, ja, type ist selbst eine Klasse, und es ist seine eigene Art. Sie werden nicht in der Lage sein, etwas wie type rein in Python neu zu erstellen, aber Python betrügt ein wenig. Um deine eigene Metaklasse in Python zu erstellen, willst du einfach nur Unterklasse.

Eine Metaklasse wird am häufigsten als Klassenfabrik verwendet. Wie Sie eine Instanz der Klasse erstellen, indem Sie die Klasse aufrufen, erstellt Python eine neue Klasse (wenn sie die 'class' -Anweisung ausführt), indem sie die Metaclass aufruft. Kombiniert mit den normalen __init__ und __new__ Methoden, können __new__ also erlauben, 'extra Dinge' beim Erstellen einer Klasse zu tun, wie die Registrierung der neuen Klasse mit einigen Registry oder sogar die Klasse mit etwas anderem ganz zu ersetzen.

Wenn die class ausgeführt wird, führt Python zuerst den Körper der class als einen normalen Codeblock aus. Der resultierende Namensraum (ein dict) enthält die Attribute der Klasse-to-be. Die Metaklasse wird bestimmt, indem man die Basisklassen der Klasse-to-be (metaclasses ist vererbt), am __metaclass__ Attribut der Klasse-to-be (falls vorhanden) oder der __metaclass__ globale Variable bestimmt. Die Metaklasse wird dann mit dem Namen, Basen und Attributen der Klasse aufgerufen, um sie zu instanziieren.

Allerdings definieren Metaclasses eigentlich den Typ einer Klasse, nicht nur eine Fabrik dafür, also kannst du viel mehr mit ihnen machen. Sie können zum Beispiel normale Methoden auf der Metaklasse definieren. Diese Metaklassemethoden sind wie Klassenzuordnungen, da sie ohne eine Instanz auf die Klasse aufgerufen werden können, aber sie sind auch nicht wie Klassenmethoden, da sie nicht auf eine Instanz der Klasse aufgerufen werden können. type.__subclasses__() ist ein Beispiel für eine Methode auf dem type metaclass. Sie können auch die normalen "magischen" Methoden wie __add__ , __iter__ und __getattr__ , um zu implementieren oder zu ändern, wie sich die Klasse verhält.

Hier ist ein aggregiertes Beispiel für die Bits und Stücke:

 def make_hook(f): """Decorator to turn 'foo' method into '__foo__'""" f.is_hook = 1 return f class MyType(type): def __new__(cls, name, bases, attrs): if name.startswith('None'): return None # Go over attributes and see if they should be renamed. newattrs = {} for attrname, attrvalue in attrs.iteritems(): if getattr(attrvalue, 'is_hook', 0): newattrs['__%s__' % attrname] = attrvalue else: newattrs[attrname] = attrvalue return super(MyType, cls).__new__(cls, name, bases, newattrs) def __init__(self, name, bases, attrs): super(MyType, self).__init__(name, bases, attrs) # classregistry.register(self, self.interfaces) print "Would register class %s now." % self def __add__(self, other): class AutoClass(self, other): pass return AutoClass # Alternatively, to autogenerate the classname as well as the class: # return type(self.__name__ + other.__name__, (self, other), {}) def unregister(self): # classregistry.unregister(self) print "Would unregister class %s now." % self class MyObject: __metaclass__ = MyType class NoneSample(MyObject): pass # Will print "NoneType None" print type(NoneSample), repr(NoneSample) class Example(MyObject): def __init__(self, value): self.value = value @make_hook def add(self, other): return self.__class__(self.value + other.value) # Will unregister the class Example.unregister() inst = Example(10) # Will fail with an AttributeError #inst.unregister() print inst + inst class Sibling(MyObject): pass ExampleSibling = Example + Sibling # ExampleSibling is now a subclass of both Example and Sibling (with no # content of its own) although it will believe it's called 'AutoClass' print ExampleSibling print ExampleSibling.__mro__ 

Klassen als Objekte

Bevor du Metaclasses verstehst, musst du Klassen in Python beherrschen. Und Python hat eine sehr merkwürdige Vorstellung davon, welche Klassen aus der Smalltalk-Sprache entlehnt sind.

In den meisten Sprachen sind Klassen nur Stücke von Code, die beschreiben, wie man ein Objekt produziert. Das stimmt auch in Python:

 >>> class ObjectCreator(object): ... pass ... >>> my_object = ObjectCreator() >>> print(my_object) <__main__.ObjectCreator object at 0x8974f2c> 

Aber Klassen sind mehr als das in Python. Klassen sind auch Objekte.

Ja, Gegenstände.

Sobald Sie die Keyword- class , führt Python es aus und erstellt ein OBJECT. Die Anleitung

 >>> class ObjectCreator(object): ... pass ... 

Schafft im Speicher ein Objekt mit dem Namen "ObjectCreator".

Dieses Objekt (die Klasse) ist selbst in der Lage, Objekte (die Instanzen) zu erstellen, und deshalb ist es eine Klasse .

Aber es ist doch ein Gegenstand und deshalb:

  • Sie können sie einer Variablen zuordnen
  • Sie können es kopieren
  • Sie können Attribute hinzufügen
  • Sie können es als Funktionsparameter übergeben

z.B:

 >>> print(ObjectCreator) # you can print a class because it's an object <class '__main__.ObjectCreator'> >>> def echo(o): ... print(o) ... >>> echo(ObjectCreator) # you can pass a class as a parameter <class '__main__.ObjectCreator'> >>> print(hasattr(ObjectCreator, 'new_attribute')) False >>> ObjectCreator.new_attribute = 'foo' # you can add attributes to a class >>> print(hasattr(ObjectCreator, 'new_attribute')) True >>> print(ObjectCreator.new_attribute) foo >>> ObjectCreatorMirror = ObjectCreator # you can assign a class to a variable >>> print(ObjectCreatorMirror.new_attribute) foo >>> print(ObjectCreatorMirror()) <__main__.ObjectCreator object at 0x8997b4c> 

Klassen dynamisch erstellen

Da Klassen Objekte sind, können Sie sie auf der Fliege erstellen, wie jedes Objekt.

Zuerst können Sie eine Klasse in einer Funktion mit class erstellen:

 >>> def choose_class(name): ... if name == 'foo': ... class Foo(object): ... pass ... return Foo # return the class, not an instance ... else: ... class Bar(object): ... pass ... return Bar ... >>> MyClass = choose_class('foo') >>> print(MyClass) # the function returns a class, not an instance <class '__main__.Foo'> >>> print(MyClass()) # you can create an object from this class <__main__.Foo object at 0x89c6d4c> 

Aber es ist nicht so dynamisch, denn du musst immer noch die ganze Klasse schreiben.

Da Klassen Objekte sind, müssen sie durch etwas erzeugt werden.

Wenn Sie das class , erstellt Python dieses Objekt automatisch. Aber wie bei den meisten Sachen in Python gibt es dir einen Weg, es manuell zu machen.

Erinnere dich an den Funktionstyp? Die gute alte Funktion, die Sie wissen lässt, welche Art ein Objekt ist:

 >>> print(type(1)) <type 'int'> >>> print(type("1")) <type 'str'> >>> print(type(ObjectCreator)) <type 'type'> >>> print(type(ObjectCreator())) <class '__main__.ObjectCreator'> 

Nun, type hat eine ganz andere Fähigkeit, es kann auch Klassen auf der Fliege. type kann die Beschreibung einer Klasse als Parameter nehmen und eine Klasse zurückgeben.

(Ich weiß, es ist dumm, dass die gleiche Funktion kann zwei völlig verschiedene Verwendungen nach den Parametern, die Sie an sie übergeben haben.Es ist ein Problem aufgrund der Rückwärts-Kompatibilität in Python)

type funktioniert auf diese Weise:

 type(name of the class, tuple of the parent class (for inheritance, can be empty), dictionary containing attributes names and values) 

z.B:

 >>> class MyShinyClass(object): ... pass 

Kann manuell so erstellt werden:

 >>> MyShinyClass = type('MyShinyClass', (), {}) # returns a class object >>> print(MyShinyClass) <class '__main__.MyShinyClass'> >>> print(MyShinyClass()) # create an instance with the class <__main__.MyShinyClass object at 0x8997cec> 

Sie werden feststellen, dass wir "MyShinyClass" als den Namen der Klasse und als die Variable verwenden, um die Klassenreferenz zu halten. Sie können anders sein, aber es gibt keinen Grund, Dinge zu komplizieren.

type akzeptiert ein Wörterbuch, um die Attribute der Klasse zu definieren. Damit:

 >>> class Foo(object): ... bar = True 

Kann übersetzt werden in:

 >>> Foo = type('Foo', (), {'bar':True}) 

Und als normale Klasse verwendet:

 >>> print(Foo) <class '__main__.Foo'> >>> print(Foo.bar) True >>> f = Foo() >>> print(f) <__main__.Foo object at 0x8a9b84c> >>> print(f.bar) True 

Und natürlich kannst du von ihm erben, also:

 >>> class FooChild(Foo): ... pass 

wäre:

 >>> FooChild = type('FooChild', (Foo,), {}) >>> print(FooChild) <class '__main__.FooChild'> >>> print(FooChild.bar) # bar is inherited from Foo True 

Irgendwann möchten Sie Ihrer Klasse Methoden hinzufügen. Definiere einfach eine Funktion mit der richtigen Signatur und ordne sie als Attribut zu.

 >>> def echo_bar(self): ... print(self.bar) ... >>> FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar}) >>> hasattr(Foo, 'echo_bar') False >>> hasattr(FooChild, 'echo_bar') True >>> my_foo = FooChild() >>> my_foo.echo_bar() True 

Und du kannst noch mehr Methoden hinzufügen, nachdem du die Klasse dynamisch erstellt hast, genau wie das Hinzufügen von Methoden zu einem normal erstellten Klassenobjekt.

 >>> def echo_bar_more(self): ... print('yet another method') ... >>> FooChild.echo_bar_more = echo_bar_more >>> hasattr(FooChild, 'echo_bar_more') True 

Sie sehen, wohin wir gehen: in Python, Klassen sind Objekte, und Sie können eine Klasse auf der Fliege, dynamisch erstellen.

Dies ist, was Python tut, wenn Sie die Keyword- class , und es tut dies, indem Sie eine Metaclass.

Was sind Metaklassen (endlich)

Metaclasses sind das "Zeug", das Klassen schafft.

Sie definieren Klassen, um Objekte zu erstellen, richtig?

Aber wir haben gelernt, dass Python-Klassen Objekte sind.

Nun, metaclasses sind, was diese Objekte zu schaffen. Sie sind die Klassenunterricht, Sie können sie so vorstellen:

 MyClass = MetaClass() MyObject = MyClass() 

Du hast diesen type gesehen, damit du so etwas machst:

 MyClass = type('MyClass', (), {}) 

Es ist, weil die Funktionstyp in der Tat eine Metaklasse ist. type ist die Metaklasse Python verwendet, um alle Klassen hinter den Kulissen zu erstellen.

Jetzt fragst du dich, warum das Heck ist es in Kleinbuchstaben geschrieben, und nicht Type ?

Nun, ich denke, es ist eine Frage der Konsequenz mit str , die Klasse, die Strings Objekte schafft, und in der Klasse, die ganzzahlige Objekte erzeugt. type ist nur die Klasse, die Klassenobjekte erzeugt.

Sie sehen das, indem Sie das Attribut __class__ überprüfen.

Alles, und ich meine alles, ist ein Gegenstand in Python. Dazu gehören Ints, Strings, Funktionen und Klassen. Alle sind Gegenstände. Und alle von ihnen wurden aus einer Klasse geschaffen:

 >>> age = 35 >>> age.__class__ <type 'int'> >>> name = 'bob' >>> name.__class__ <type 'str'> >>> def foo(): pass >>> foo.__class__ <type 'function'> >>> class Bar(object): pass >>> b = Bar() >>> b.__class__ <class '__main__.Bar'> 

Nun, was ist die __class__ von jedem __class__ ?

 >>> age.__class__.__class__ <type 'type'> >>> name.__class__.__class__ <type 'type'> >>> foo.__class__.__class__ <type 'type'> >>> b.__class__.__class__ <type 'type'> 

Also, eine Metaklasse ist nur das Zeug, das Klassenobjekte erzeugt.

Sie können es als "Klassenfabrik" bezeichnen, wenn Sie es wünschen.

type ist die eingebaute Metaclass Python verwendet, aber natürlich können Sie Ihre eigene Metaclass erstellen.

Das Attribut __metaclass__

Sie können ein Attribut __metaclass__ hinzufügen, wenn Sie eine Klasse schreiben:

 class Foo(object): __metaclass__ = something... [...] 

Wenn Sie dies tun, wird Python die Metaklasse verwenden, um die Klasse Foo zu erstellen.

Vorsicht, es ist knifflig.

Sie schreiben zuerst class Foo(object) , aber das Klassenobjekt Foo wird noch nicht im Speicher angelegt.

Python sucht nach __metaclass__ in der Klassendefinition. Wenn es es findet, wird es es verwenden, um die Objektklasse Foo zu erstellen. Wenn dies nicht der Fall ist, wird es den type , um die Klasse zu erstellen.

Lesen Sie das mehrmals.

Wenn Sie das tun:

 class Foo(Bar): pass 

Python macht folgendes:

Gibt es ein __metaclass__ Attribut in Foo ?

Wenn ja, schaffe im Speicher ein Klassenobjekt (ich sagte ein Klassenobjekt, bleib bei mir hier), mit dem Namen Foo indem __metaclass__ was in __metaclass__ .

Wenn Python nicht finden kann __metaclass__ , wird es nach einem __metaclass__ auf der MODULE-Ebene suchen und versuchen, das gleiche zu tun (aber nur für Klassen, die nichts erben, im Grunde altmodische Klassen).

Dann, wenn es überhaupt keine __metaclass__ finden kann, wird es die Bar 's (die erste übergeordnete) eigene Metaklasse (die der Standardtyp sein könnte), um das Klassenobjekt zu erstellen.

Sei vorsichtig, dass das Attribut __metaclass__ nicht vererbt wird, wird die Metaklasse des Elternteils ( Bar.__class__ ) sein. Wenn Bar ein __metaclass__ Attribut verwendet hat, das Bar mit type() (und nicht type.__new__() ) erstellt hat, werden die Unterklassen dieses Verhalten nicht erben.

Nun ist die große Frage, was kannst du in __metaclass__ ?

Die Antwort ist: etwas, das eine Klasse schaffen kann.

Und was kann eine Klasse schaffen? type , oder irgendetwas, das es subklassen oder verwendet.

Benutzerdefinierte metaclasses

Der Hauptzweck einer Metaklasse ist es, die Klasse automatisch zu ändern, wenn sie erstellt wird.

Sie tun dies normalerweise für APIs, wo Sie Klassen erstellen möchten, die dem aktuellen Kontext entsprechen.

Stellen Sie sich ein dummes Beispiel vor, wo Sie entscheiden, dass alle Klassen in Ihrem Modul ihre Attribute in Großbuchstaben geschrieben haben sollen. Es gibt mehrere Möglichkeiten, dies zu tun, aber eine Möglichkeit ist, __metaclass__ auf der Modulebene zu setzen.

Auf diese Weise werden alle Klassen dieses Moduls mit dieser Metaklasse erstellt, und wir müssen nur sagen, dass die Metaklasse alle Attribute in Großbuchstaben umwandelt.

Zum Glück, __metaclass__ kann eigentlich ein abrufbarer sein, es muss nicht eine formale Klasse sein (ich weiß, etwas mit 'Klasse' in seinem Namen muss nicht eine Klasse sein, gehen Figur … aber es ist hilfreich).

So beginnen wir mit einem einfachen Beispiel, indem wir eine Funktion verwenden.

 # the metaclass will automatically get passed the same argument # that you usually pass to `type` def upper_attr(future_class_name, future_class_parents, future_class_attr): """ Return a class object, with the list of its attribute turned into uppercase. """ # pick up any attribute that doesn't start with '__' and uppercase it uppercase_attr = {} for name, val in future_class_attr.items(): if not name.startswith('__'): uppercase_attr[name.upper()] = val else: uppercase_attr[name] = val # let `type` do the class creation return type(future_class_name, future_class_parents, uppercase_attr) __metaclass__ = upper_attr # this will affect all classes in the module class Foo(): # global __metaclass__ won't work with "object" though # but we can define __metaclass__ here instead to affect only this class # and this will work with "object" children bar = 'bip' print(hasattr(Foo, 'bar')) # Out: False print(hasattr(Foo, 'BAR')) # Out: True f = Foo() print(f.BAR) # Out: 'bip' 

Nun, machen wir genau das gleiche, aber mit einer echten Klasse für eine Metaklasse:

 # remember that `type` is actually a class like `str` and `int` # so you can inherit from it class UpperAttrMetaclass(type): # __new__ is the method called before __init__ # it's the method that creates the object and returns it # while __init__ just initializes the object passed as parameter # you rarely use __new__, except when you want to control how the object # is created. # here the created object is the class, and we want to customize it # so we override __new__ # you can do some stuff in __init__ too if you wish # some advanced use involves overriding __call__ as well, but we won't # see this def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): uppercase_attr = {} for name, val in future_class_attr.items(): if not name.startswith('__'): uppercase_attr[name.upper()] = val else: uppercase_attr[name] = val return type(future_class_name, future_class_parents, uppercase_attr) 

Aber das ist nicht wirklich OOP. Wir rufen den type direkt an und wir überschreiben nicht oder nennen das Elternteil __new__ . Machen wir das:

 class UpperAttrMetaclass(type): def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr): uppercase_attr = {} for name, val in future_class_attr.items(): if not name.startswith('__'): uppercase_attr[name.upper()] = val else: uppercase_attr[name] = val # reuse the type.__new__ method # this is basic OOP, nothing magic in there return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr) 

Sie haben vielleicht das Extra-Argument upperattr_metaclass bemerkt. Es gibt nichts Besonderes: __new__ empfängt immer die Klasse, die es definiert hat, als erster Parameter. So wie Sie self für gewöhnliche Methoden haben, die die Instanz als ersten Parameter oder die definierende Klasse für Klassenmethoden erhalten.

Natürlich sind die Namen, die ich hier benutzt habe, lange um der Klarheit willen, aber wie für sich self , alle Argumente haben konventionelle Namen. So würde eine echte Produktion metaclass so aussehen:

 class UpperAttrMetaclass(type): def __new__(cls, clsname, bases, dct): uppercase_attr = {} for name, val in dct.items(): if not name.startswith('__'): uppercase_attr[name.upper()] = val else: uppercase_attr[name] = val return type.__new__(cls, clsname, bases, uppercase_attr) 

Wir können es noch sauberer machen, indem wir super benutzen, was die Vererbung erleichtert (denn ja, man kann Metaclasses haben, von metaclasses erben, vom Typ erben):

 class UpperAttrMetaclass(type): def __new__(cls, clsname, bases, dct): uppercase_attr = {} for name, val in dct.items(): if not name.startswith('__'): uppercase_attr[name.upper()] = val else: uppercase_attr[name] = val return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr) 

Das ist es. Es gibt wirklich nichts mehr über metaclasses.

Der Grund für die Komplexität des Codes, der Metaclasses verwendet, ist nicht wegen der Metaclasses, sondern weil Sie in der Regel Metaclasses verwenden, um verdrehte Sachen zu tun, die sich auf Introspektion verlassen, Vererbung manipulieren, Vars wie __dict__ , etc.

In der Tat sind Metaklassen besonders nützlich, um schwarze Magie zu machen, und daher komplizierte Sachen. Aber selbst sind sie einfach:

  • Abfangen einer Klassenerstellung
  • Modifizieren Sie die Klasse
  • Gib die modifizierte Klasse zurück

Warum würden Sie Metaclasses Klassen anstelle von Funktionen verwenden?

Da __metaclass__ irgendwelche __metaclass__ annehmen kann, warum würdest du eine Klasse benutzen, da es offensichtlich komplizierter ist?

Es gibt mehrere Gründe dazu:

  • Die Absicht ist klar. Wenn du UpperAttrMetaclass(type) liest, UpperAttrMetaclass(type) du, was folgen wird
  • Du kannst OOP verwenden. Metaclass kann von metaclass erben, übergeordnete übergeordnete Methoden. Metaclasses können sogar Metaklassen benutzen.
  • Kinder einer Klasse werden Instanzen ihrer Metaklasse sein, wenn du eine Metaklassenklasse spezifiziert hast, aber nicht mit einer Metaklass-Funktion.
  • Sie können Ihren Code besser strukturieren. Sie verwenden nie Metaklassen für etwas so trivial wie das obige Beispiel. Es ist normalerweise etwas kompliziert. Mit der Fähigkeit, mehrere Methoden zu machen und gruppieren sie in einer Klasse ist sehr nützlich, um den Code leichter zu lesen.
  • Sie können auf __new__ , __init__ und __call__ . Das erlaubt Ihnen, verschiedene Sachen zu machen. Auch wenn Sie in der Regel alles in __new__ tun können, sind einige Leute einfach nur bequem mit __init__ .
  • Diese heißen metaclasses, verdammt noch mal! Es muss etwas bedeuten!

Warum würden Sie Metaclasses benutzen?

Jetzt die große Frage. Warum würdest du etwas obskure fehleranfällige Funktion verwenden?

Nun, in der Regel nicht:

Metaclasses sind tiefer Magie, die 99% der Nutzer sich niemals Sorgen machen sollten. Wenn du dich fragst, ob du sie brauchst, dann tust du nicht (die Leute, die sie wirklich brauchen, wissen mit Sicherheit, dass sie sie brauchen und brauchen keine Erklärung darüber, warum).

Python Guru Tim Peters

Der wichtigste Anwendungsfall für eine Metaklasse ist die Erstellung einer API. Ein typisches Beispiel dafür ist das Django ORM.

Es erlaubt Ihnen, so etwas zu definieren:

 class Person(models.Model): name = models.CharField(max_length=30) age = models.IntegerField() 

Aber wenn du das machst:

 guy = Person(name='bob', age='35') print(guy.age) 

Es wird kein IntegerField Objekt zurückgeben. Es wird ein int und kann es sogar direkt aus der Datenbank nehmen.

Dies ist möglich, weil models.Model definiert __metaclass__ und es verwendet einige Magie, die die Person Sie gerade definiert mit einfachen Anweisungen in einen komplexen Haken zu einem Datenbank-Feld.

Django macht etwas komplexes Aussehen einfach, indem es eine einfache API und mit Metaclasses, die Wiederherstellung von Code aus dieser API, um die eigentliche Arbeit hinter den Kulissen zu machen.

Das letzte Wort

Zuerst wissen Sie, dass Klassen Objekte sind, die Instanzen erzeugen können.

In der Tat sind Klassen selbst Fälle. Von metaclasses

 >>> class Foo(object): pass >>> id(Foo) 142630324 

Alles ist ein Gegenstand in Python, und sie sind alle Instanzen von Klassen oder Instanzen von Metaklassen.

Mit Ausnahme von type .

type ist eigentlich seine eigene Metaklasse. Dies ist nicht etwas, was man in reiner Python reproduzieren könnte, und wird durch Betrug ein wenig auf der Implementierung Ebene getan.

Zweitens sind Metaklassen kompliziert. Sie können sie nicht für sehr einfache Klassenänderungen verwenden. Sie können Klassen ändern, indem Sie zwei verschiedene Techniken verwenden:

  • Affenpatching
  • Klasse Dekorateure

99% der Zeit, die Sie Klassenänderung benötigen, sind Sie besser dran mit diesen.

Aber 99% der Zeit, Sie brauchen keine Klassenänderung überhaupt.

Beachten Sie, diese Antwort ist für Python 2.x, wie es im Jahr 2008 geschrieben wurde, sind Metaklassen etwas anders in 3.x, siehe die Kommentare.

Metaclasses sind die geheime Sauce, die "Klasse" Arbeit machen. Die Standard-Metaklasse für ein neues Style-Objekt heißt 'type'.

 class type(object) | type(object) -> the object's type | type(name, bases, dict) -> a new type 

Metaclasses nehmen 3 args. ' Name ', ' bases ' und ' dict '

Hier beginnt das Geheimnis. Suchen Sie nach wo Name, Basen und das Dict kommen aus in diesem Beispiel Klasse Definition.

 class ThisIsTheName(Bases, Are, Here): All_the_code_here def doesIs(create, a): dict 

Lets definieren eine Metaklasse, die zeigt, wie ' class: ' es anruft.

 def test_metaclass(name, bases, dict): print 'The Class Name is', name print 'The Class Bases are', bases print 'The dict has', len(dict), 'elems, the keys are', dict.keys() return "yellow" class TestName(object, None, int, 1): __metaclass__ = test_metaclass foo = 1 def baz(self, arr): pass print 'TestName = ', repr(TestName) # output => The Class Name is TestName The Class Bases are (<type 'object'>, None, <type 'int'>, 1) The dict has 4 elems, the keys are ['baz', '__module__', 'foo', '__metaclass__'] TestName = 'yellow' 

Und nun, ein Beispiel, das eigentlich etwas bedeutet, wird dies automatisch die Variablen in der Liste "Attribute" auf die Klasse gesetzt und auf Keine gesetzt.

 def init_attributes(name, bases, dict): if 'attributes' in dict: for attr in dict['attributes']: dict[attr] = None return type(name, bases, dict) class Initialised(object): __metaclass__ = init_attributes attributes = ['foo', 'bar', 'baz'] print 'foo =>', Initialised.foo # output=> foo => None 

Beachten Sie, dass das magische Verhalten, das "Initalisiert" gewinnt, indem man die init_attributes nicht auf eine Unterklasse von Initalisiert übergibt.

Hier ist ein noch konkreteres Beispiel, das zeigt, wie Sie Untertypen 'type' machen können, um eine Metaklasse zu erstellen, die eine Aktion ausführt, wenn die Klasse erstellt wird. Das ist ziemlich knifflig:

 class MetaSingleton(type): instance = None def __call__(cls, *args, **kw): if cls.instance is None: cls.instance = super(MetaSingleton, cls).__call__(*args, **kw) return cls.instance class Foo(object): __metaclass__ = MetaSingleton a = Foo() b = Foo() assert a is b 

Eine Verwendung für metaclasses ist das Hinzufügen neuer Eigenschaften und Methoden zu einer Instanz automatisch.

Zum Beispiel, wenn man sich Django-Modelle anschaut, sieht ihre Definition ein bisschen verwirrend aus. Es sieht so aus, als ob Sie nur Klasseneigenschaften definieren:

 class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) 

Zur Laufzeit sind die Person-Objekte jedoch mit allen möglichen nützlichen Methoden gefüllt. Sehen Sie die Quelle für einige erstaunliche metaclassery.

Andere haben erklärt, wie Metaclasses arbeiten und wie sie in das Python-System passen. Hier ist ein Beispiel dafür, wofür man sein kann. In einem Test-Framework, das ich schrieb, wollte ich die Reihenfolge verfolgen, in der Klassen definiert wurden, so dass ich sie später in dieser Reihenfolge instanziieren konnte. Ich fand es am einfachsten, dies mit einer Metaklasse zu tun.

 class MyMeta(type): counter = 0 def __init__(cls, name, bases, dic): type.__init__(cls, name, bases, dic) cls._order = MyMeta.counter MyMeta.counter += 1 class MyType(object): # Python 2 __metaclass__ = MyMeta class MyType(metaclass=MyMeta): # Python 3 pass 

Alles, was eine Unterklasse von MyType ist, bekommt dann ein Klassenattribut _order , das die Reihenfolge aufzeichnet, in der die Klassen definiert wurden.

Ich denke, die ONLamp Einführung in Metaclass Programmierung ist gut geschrieben und gibt eine wirklich gute Einführung in das Thema, obwohl schon mehrere Jahre alt bereits.

http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html

Kurz gesagt: Eine Klasse ist eine Blaupause für die Erstellung einer Instanz, eine Metaklasse ist eine Blaupause für die Schaffung einer Klasse. Es ist leicht zu sehen, dass in Python-Klassen auch erstklassige Objekte sein müssen, um dieses Verhalten zu ermöglichen.

Ich habe noch nie eine selbst geschrieben, aber ich denke, einer der schönsten Gebrauch von Metaklassen kann im Django-Rahmen gesehen werden . Die Modellklassen verwenden einen metaclass-Ansatz, um einen deklarativen Stil des Schreibens neuer Modelle oder Formulare zu ermöglichen. Während die Metaklasse die Klasse kreiert, erhalten alle Mitglieder die Möglichkeit, die Klasse selbst anzupassen.

  • Erstellen eines neuen Modells
  • Die Metaklasse, die dies ermöglicht

Die Sache, die noch zu sagen ist: Wenn Sie nicht wissen, was Metaclasses sind, ist die Wahrscheinlichkeit, dass Sie sie nicht brauchen, ist 99%.

Was sind Metaklassen? Wofür verwenden Sie sie?

Eine Klasse ist eine Instanz, da eine Metaklasse eine Klasse ist.

Setzen Sie einen anderen Weg, eine Klasse ist eine Instanz einer Metaklasse.

Setzen Sie einen dritten Weg, eine Metaklasse ist eine Klasse Klasse.

Noch hoffnungslos verwirrt So war ich, bis ich folgendes gelernt und gezeigt habe, wie man eigentlich metaclasses benutzen kann:

Sie verwenden eine Metaklasse jedes Mal, wenn Sie eine Klasse erstellen:

Wenn Sie zB eine Klassendefinition erstellen,

 class Foo(object): 'demo' 

Es ist das gleiche wie funktionell aufrufenden type mit den entsprechenden Argumenten und das Zuordnen des Ergebnisses zu einer Variablen dieses Namens:

 name = 'Foo' bases = (object,) namespace = {'__doc__': 'demo'} Foo = type(name, bases, namespace) 

Anmerkung, manche Sachen werden automatisch dem __dict__ hinzugefügt, dh dem Namespace:

 >>> Foo.__dict__ dict_proxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': 'demo'}) 

Die Metaklasse des Objekts, das wir erstellt haben, ist in beiden Fällen type .

Wir können den type genau wie jede andere Klassendefinition erweitern:

Hier ist der Standard __repr__ der Klassen:

 >>> Foo <class '__main__.Foo'> 

Eines der wertvollsten Dinge, die wir standardmäßig beim Schreiben eines Python-Objekts tun können, ist, es mit einem guten __repr__ . Wenn wir help(repr) , erfahren wir, dass es einen guten Test für ein __repr__ , das auch einen Test für Gleichheit erfordert – obj == eval(repr(obj)) . Die folgende einfache Implementierung von __repr__ und __eq__ für Klasseninstanzen unserer Typklasse gibt uns eine Demonstration, die sich auf den Standard __repr__ der Klassen verbessern kann:

 class Type(type): def __repr__(cls): """ >>> Baz Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None}) >>> eval(repr(Baz)) Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None}) """ metaname = type(cls).__name__ name = cls.__name__ parents = ', '.join(b.__name__ for b in cls.__bases__) if parents: parents += ',' namespace = ', '.join(': '.join( (repr(k), repr(v) if not isinstance(v, type) else v.__name__)) for k, v in cls.__dict__.items()) return '{0}(\'{1}\', ({2}), {{{3}}})'.format(metaname, name, parents, namespace) def __eq__(cls, other): """ >>> Baz == eval(repr(Baz)) True """ return (cls.__name__, cls.__bases__, cls.__dict__) == ( other.__name__, other.__bases__, other.__dict__) 

So, jetzt, wenn wir ein Objekt mit dieser Metaklasse erstellen, bietet das __repr__ auf der Kommandozeile eine viel weniger hässliche Sicht als die Voreinstellung:

 >>> class Bar(object): pass >>> Baz = Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None}) >>> Baz Type('Baz', (Foo, Bar,), {'__module__': '__main__', '__doc__': None}) 

Mit einem für die __repr__ definierten __repr__ haben wir eine stärkere Fähigkeit, unseren Code zu debuggen.

Eine erwartete Verwendung: __prepare__ ein Namespace

Wenn wir zum Beispiel wissen wollen, in welcher Reihenfolge die Methoden einer Klasse erstellt werden, könnten wir als Namensraum der Klasse einen geordneten Dict liefern. Wir würden das mit __prepare__ tun, das den Namespace dict für die Klasse zurückgibt, wenn es in Python 3 implementiert ist :

 from collections import OrderedDict class OrderedType(Type): @classmethod def __prepare__(metacls, name, bases, **kwargs): return OrderedDict() def __new__(cls, name, bases, namespace, **kwargs): result = Type.__new__(cls, name, bases, dict(namespace)) result.members = tuple(namespace) return result 

Und Gebrauch:

 class OrderedMethodsObject(object, metaclass=OrderedType): def method1(self): pass def method2(self): pass def method3(self): pass def method4(self): pass 

Und jetzt haben wir eine Aufzeichnung der Reihenfolge, in der diese Methoden (und andere Klassenattribute) erstellt wurden:

 >>> OrderedMethodsObject.members ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4') 

Beachten Sie, dass dieses Beispiel aus den docs angepasst wurde.

Also, was wir taten, war Instanziierung einer Metaklasse durch die Schaffung einer Klasse. Wir können auch die Metaklasse behandeln, wie wir jede andere Klasse haben würden. Es hat eine Methode Auflösung Reihenfolge:

 >>> inspect.getmro(OrderedType) (<class '__main__.OrderedType'>, <class '__main__.Type'>, <class 'type'>, <class 'object'>) 

Und es hat ungefähr das richtige repr (was wir nicht mehr aussprechen können, wenn wir nicht einen Weg finden können, unsere Funktionen darzustellen.):

 >>> OrderedMethodsObject OrderedType('OrderedMethodsObject', (object,), {'method1': <function OrderedMethodsObject.method1 at 0x0000000002DB01E0>, 'members': ('__module__', '__qualname__', 'method1', 'method2', 'method3', 'method4'), 'method3': <function OrderedMet hodsObject.method3 at 0x0000000002DB02F0>, 'method2': <function OrderedMethodsObject.method2 at 0x0000000002DB0268>, '__module__': '__main__', '__weakref__': <attribute '__weakref__' of 'OrderedMethodsObject' objects>, '__doc__': None, '__d ict__': <attribute '__dict__' of 'OrderedMethodsObject' objects>, 'method4': <function OrderedMethodsObject.method4 at 0x0000000002DB0378>}) 

Python 3 update

There are (at this point) two key methods in a metaclass:

  • __prepare__ , and
  • __new__

__prepare__ lets you supply a custom mapping (such as an OrderedDict ) to be used as the namespace while the class is being created. You must return an instance of whatever namespace you choose. If you don't implement __prepare__ a normal dict is used.

__new__ is responsible for the actual creation/modification of the final class.

A bare-bones, do-nothing-extra metaclass would like:

 class Meta(type): def __prepare__(metaclass, cls, bases): return dict() def __new__(metacls, cls, bases, clsdict): return super().__new__(metacls, cls, bases, clsdict) 

A simple example:

Say you want some simple validation code to run on your attributes — like it must always be an int or a str . Without a metaclass, your class would look something like:

 class Person: weight = ValidateType('weight', int) age = ValidateType('age', int) name = ValidateType('name', str) 

As you can see, you have to repeat the name of the attribute twice. This makes typos possible along with irritating bugs.

A simple metaclass can address that problem:

 class Person(metaclass=Validator): weight = ValidateType(int) age = ValidateType(int) name = ValidateType(str) 

This is what the metaclass would look like (not using __prepare__ since it is not needed):

 class Validator(type): def __new__(metacls, cls, bases, clsdict): # search clsdict looking for ValidateType descriptors for name, attr in clsdict.items(): if isinstance(attr, ValidateType): attr.name = name attr.attr = '_' + name # create final class and return it return super().__new__(metacls, cls, bases, clsdict) 

A sample run of:

 p = Person() p.weight = 9 print(p.weight) p.weight = '9' 

produces:

 9 Traceback (most recent call last): File "simple_meta.py", line 36, in <module> p.weight = '9' File "simple_meta.py", line 24, in __set__ (self.name, self.type, value)) TypeError: weight must be of type(s) <class 'int'> (got '9') 

Note : This example is simple enough it could have also been accomplished with a class decorator, but presumably an actual metaclass would be doing much more.

The 'ValidateType' class for reference:

 class ValidateType: def __init__(self, type): self.name = None # will be set by metaclass self.attr = None # will be set by metaclass self.type = type def __get__(self, inst, cls): if inst is None: return self else: return inst.__dict__[self.attr] def __set__(self, inst, value): if not isinstance(value, self.type): raise TypeError('%s must be of type(s) %s (got %r)' % (self.name, self.type, value)) else: inst.__dict__[self.attr] = value 

A metaclass is a class that tells how (some) other class should be created.

This is a case where I saw metaclass as a solution to my problem: I had a really complicated problem, that probably could have been solved differently, but I chose to solve it using a metaclass. Because of the complexity, it is one of the few modules I have written where the comments in the module surpass the amount of code that has been written. Here it is…

 #!/usr/bin/env python # Copyright (C) 2013-2014 Craig Phillips. All rights reserved. # This requires some explaining. The point of this metaclass excercise is to # create a static abstract class that is in one way or another, dormant until # queried. I experimented with creating a singlton on import, but that did # not quite behave how I wanted it to. See now here, we are creating a class # called GsyncOptions, that on import, will do nothing except state that its # class creator is GsyncOptionsType. This means, docopt doesn't parse any # of the help document, nor does it start processing command line options. # So importing this module becomes really efficient. The complicated bit # comes from requiring the GsyncOptions class to be static. By that, I mean # any property on it, may or may not exist, since they are not statically # defined; so I can't simply just define the class with a whole bunch of # properties that are @property @staticmethods. # # So here's how it works: # # Executing 'from libgsync.options import GsyncOptions' does nothing more # than load up this module, define the Type and the Class and import them # into the callers namespace. Simple. # # Invoking 'GsyncOptions.debug' for the first time, or any other property # causes the __metaclass__ __getattr__ method to be called, since the class # is not instantiated as a class instance yet. The __getattr__ method on # the type then initialises the class (GsyncOptions) via the __initialiseClass # method. This is the first and only time the class will actually have its # dictionary statically populated. The docopt module is invoked to parse the # usage document and generate command line options from it. These are then # paired with their defaults and what's in sys.argv. After all that, we # setup some dynamic properties that could not be defined by their name in # the usage, before everything is then transplanted onto the actual class # object (or static class GsyncOptions). # # Another piece of magic, is to allow command line options to be set in # in their native form and be translated into argparse style properties. # # Finally, the GsyncListOptions class is actually where the options are # stored. This only acts as a mechanism for storing options as lists, to # allow aggregation of duplicate options or options that can be specified # multiple times. The __getattr__ call hides this by default, returning the # last item in a property's list. However, if the entire list is required, # calling the 'list()' method on the GsyncOptions class, returns a reference # to the GsyncListOptions class, which contains all of the same properties # but as lists and without the duplication of having them as both lists and # static singlton values. # # So this actually means that GsyncOptions is actually a static proxy class... # # ...And all this is neatly hidden within a closure for safe keeping. def GetGsyncOptionsType(): class GsyncListOptions(object): __initialised = False class GsyncOptionsType(type): def __initialiseClass(cls): if GsyncListOptions._GsyncListOptions__initialised: return from docopt import docopt from libgsync.options import doc from libgsync import __version__ options = docopt( doc.__doc__ % __version__, version = __version__, options_first = True ) paths = options.pop('<path>', None) setattr(cls, "destination_path", paths.pop() if paths else None) setattr(cls, "source_paths", paths) setattr(cls, "options", options) for k, v in options.iteritems(): setattr(cls, k, v) GsyncListOptions._GsyncListOptions__initialised = True def list(cls): return GsyncListOptions def __getattr__(cls, name): cls.__initialiseClass() return getattr(GsyncListOptions, name)[-1] def __setattr__(cls, name, value): # Substitut option names: --an-option-name for an_option_name import re name = re.sub(r'^__', "", re.sub(r'-', "_", name)) listvalue = [] # Ensure value is converted to a list type for GsyncListOptions if isinstance(value, list): if value: listvalue = [] + value else: listvalue = [ None ] else: listvalue = [ value ] type.__setattr__(GsyncListOptions, name, listvalue) # Cleanup this module to prevent tinkering. import sys module = sys.modules[__name__] del module.__dict__['GetGsyncOptionsType'] return GsyncOptionsType # Our singlton abstract proxy class. class GsyncOptions(object): __metaclass__ = GetGsyncOptionsType() 

Role of a metaclass's __call__() method when creating a class instance

If you've done Python programming for more than a few months you'll eventually stumble upon code that looks like this:

 # define a class class SomeClass(object): # ... # some definition here ... # ... # create an instance of it instance = SomeClass() # then call the object as if it's a function result = instance('foo', 'bar') 

The latter is possible when you implement the __call__() magic method on the class.

 class SomeClass(object): # ... # some definition here ... # ... def __call__(self, foo, bar): return bar + foo 

The __call__() method is invoked when an instance of a class is used as a callable. But as we've seen from previous answers a class itself is an instance of a metaclass, so when we use the class as a callable (ie when we create an instance of it) we're actually calling its metaclass's __call__() method. At this point most Python programmers are a bit confused because they've been told that when creating an instance like this instance = SomeClass() you're calling it's __init__() method. Some who've dug a bit deeper know that before __init__() there's __new__() . Well, today another layer of truth is being revealed, before __new__() there's the metaclass's __call__() .

Let's study the method call chain from specifically the perspective of creating an instance of a class.

This is a metaclass that logs exactly the moment before an instance is created and the moment it's about to return it.

 class Meta_1(type): def __call__(cls): print "Meta_1.__call__() before creating an instance of ", cls instance = super(Meta_1, cls).__call__() print "Meta_1.__call__() about to return instance." return instance 

This is a class that uses that metaclass

 class Class_1(object): __metaclass__ = Meta_1 def __new__(cls): print "Class_1.__new__() before creating an instance." instance = super(Class_1, cls).__new__(cls) print "Class_1.__new__() about to return instance." return instance def __init__(self): print "entering Class_1.__init__() for instance initialization." super(Class_1,self).__init__() print "exiting Class_1.__init__()." 

And now let's create an instance of Class_1

 instance = Class_1() # Meta_1.__call__() before creating an instance of <class '__main__.Class_1'>. # Class_1.__new__() before creating an instance. # Class_1.__new__() about to return instance. # entering Class_1.__init__() for instance initialization. # exiting Class_1.__init__(). # Meta_1.__call__() about to return instance. 

The code above doesn't actually do anything other than logging the task and then delegating the actual work to the parent (ie keeping the default behavior). So with type being Meta_1 's parent class, we can imagine that this would be the pseudo implementation of type.__call__() :

 class type: def __call__(cls, *args, **kwarg): # ... maybe a few things done to cls here # then we call __new__() on the class to create an instance instance = cls.__new__(cls, *args, **kwargs) # ... maybe a few things done to the instance here # then we initialize the instance with its __init__() method instance.__init__(*args, **kwargs) # ... maybe a few more things done to instance here # then we return it return instance 

We can see that the metaclass's __call__() method is the one that's called first. It then delegates creation of the instance to the class's __new__() method and initialization to the instance's __init__() . It's also the one that ultimately returns the instance.

From the above it stems that the metaclass's __call__() is also given the opportunity to decide whether or not a call to Class_1.__new__() or Class_1.__init__() will eventually be made. Over the course of its execution it could actually return an object that hasn't been touched by either of these methods. Take for example this approach to the singleton pattern:

 class Meta_2(type): singletons = {} def __call__(cls, *args, **kwargs): if cls in Meta_2.singletons: # we return the only instance and skip a call to __new__() # and __init__() print ("{} singleton returning from Meta_2.__call__(), " "skipping creation of new instance.".format(cls)) return Meta_2.singletons[cls] # else if the singleton isn't present we proceed as usual print "Meta_2.__call__() before creating an instance." instance = super(Meta_2, cls).__call__(*args, **kwargs) Meta_2.singletons[cls] = instance print "Meta_2.__call__() returning new instance." return instance class Class_2(object): __metaclass__ = Meta_2 def __new__(cls, *args, **kwargs): print "Class_2.__new__() before creating instance." instance = super(Class_2, cls).__new__(cls) print "Class_2.__new__() returning instance." return instance def __init__(self, *args, **kwargs): print "entering Class_2.__init__() for initialization." super(Class_2, self).__init__() print "exiting Class_2.__init__()." 

Let's observe what happens when repeatedly trying to create an object of type Class_2

 a = Class_2() # Meta_2.__call__() before creating an instance. # Class_2.__new__() before creating instance. # Class_2.__new__() returning instance. # entering Class_2.__init__() for initialization. # exiting Class_2.__init__(). # Meta_2.__call__() returning new instance. b = Class_2() # <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance. c = Class_2() # <class '__main__.Class_2'> singleton returning from Meta_2.__call__(), skipping creation of new instance. a is b is c # True 

The tl;dr version

The type(obj) function gets you the type of an object.

The type() of a class is its metaclass .

To use a metaclass:

 class Foo(object): __metaclass__ = MyMetaClass 

type is actually a metaclass — a class that creates another classes. Most metaclass are the subclasses of type . The metaclass receives the new class as its first argument and provide access to class object with details as mentioned below:

 >>> class MetaClass(type): ... def __init__(cls, name, bases, attrs): ... print ('class name: %s' %name ) ... print ('Defining class %s' %cls) ... print('Bases %s: ' %sbases) ... print('Attributes') ... for (name, value) in attrs.items(): ... print ('%s :%r' %(name, value)) ... >>> class NewClass(object, metaclass=MetaClass): ... get_choch='dairy' ... class name: NewClass Bases <class 'object'>: Defining class <class 'NewClass'> get_choch :'dairy' __module__ :'builtins' __qualname__ :'NewClass' 

Notice that the class was not instantiated at any time; the simple act of creating the class triggered execution of the metaclass .

A metaclass is essentially an abstract base class–a concept taught in most intermediate computer programming courses.

Python classes are themselves objects – as in instance – of their meta-class.

The default metaclass, which is applied when when you determine classes as:

 class foo: ... 

meta class are used to apply some rule to an entire set of classes. For example, suppose you're building an ORM to access a database, and you want records from each table to be of a class mapped to that table (based on fields, business rules, etc..,), a possible use of metaclass is for instance, connection pool logic, which is share by all classes of record from all tables. Another use is logic to to support foreign keys, which involves multiple classes of records.

when you define metaclass, you subclass type, and can overrided the following magic methods to insert your logic.

 class somemeta(type): __new__(mcs, name, bases, clsdict): """ mcs: is the base metaclass, in this case type. name: name of the new class, as provided by the user. bases: tuple of base classes clsdict: a dictionary containing all methods and attributes defined on class you must return a class object by invoking the __new__ constructor on the base metaclass. ie: return type.__call__(mcs, name, bases, clsdict). in the following case: class foo(baseclass): __metaclass__ = somemeta an_attr = 12 def bar(self): ... @classmethod def foo(cls): ... arguments would be : ( somemeta, "foo", (baseclass, baseofbase,..., object), {"an_attr":12, "bar": <function>, "foo": <bound class method>} you can modify any of these values before passing on to type """ return type.__call__(mcs, name, bases, clsdict) def __init__(self, name, bases, clsdict): """ called after type has been created. unlike in standard classes, __init__ method cannot modify the instance (cls) - and should be used for class validaton. """ pass def __prepare__(): """ returns a dict or something that can be used as a namespace. the type will then attach methods and attributes from class definition to it. call order : somemeta.__new__ -> type.__new__ -> type.__init__ -> somemeta.__init__ """ return dict() def mymethod(cls): """ works like a classmethod, but for class objects. Also, my method will not be visible to instances of cls. """ pass 

anyhow, those two are the most commonly used hooks. metaclassing is powerful, and above is nowhere near and exhaustive list of uses for metaclassing.

Python ist die beste Programmiersprache der Welt.