Redirected from page "Meta Klassen"

Clear message
Metaklassen

Zum Verständnis von Metaklassen

Jedes Objekt in Python hat einen Typ, der einen Großteil seines Verhaltens bestimmt (Methoden, Konstruktor, Deskriptoren).

Beispiele: 1 ist vom Typ int. Wenn Foo eine Klasse ist, dann ist Foo(), also eine Instanz, vom Typ Foo. Definiert Foo eine Methode bar(self), so kann diese mit Foo().bar() aufgerufen werden.

Nun sind natürlich auch Klassen an sich ein Objekt und haben deshalb einen Typ. Dieser heißt normalerweise bei New-Style Klassen type (bei alten Klassen types.ClassType) -- allerdings muss er das nicht, denn er kann bei der Erstellung einer Klasse angegeben werden!

Dazu muss man wissen, dass eine Klassendeklaration wie

   1 class Foo(object):
   2     a = 1

in Wirklichkeit in dieses Konstrukt kompiliert wird:

   1 Foo = type('Foo', (object,), {'a': 1})

Wie man sieht, wird hier eine Instanz von type erstellt, mit drei Argumenten: Name der Klasse, Basisklassen und ein Dictionary mit den Attributen der Klasse (hier nur ein Datenattribut, mit Funktionen (=Methoden) wird genauso verfahren). Foo ist also eine Instanz von type, und das macht es zu einer Klasse. Man sagt, type ist die Metaklasse von Foo.

Jetzt kommt der Knackpunkt: Man kann nicht nur die Argumente, die type übergeben werden, bestimmen, sondern auch eine beliebige Klasse, die instanziert wird, wenn die Klasse Foo erstellt wird! Dazu verwendet man das spezielle Attribut __metaclass__:

   1 class Foo(object):
   2     __metaclass__ = MyMetaclass
   3     a = 1

wird kompiliert zu

   1 Foo = MyMetaclass('Foo', (object,), {'a': 1})

Indem man also eine Klasse MyMetaclass definiert, kann man das Verhalten der Klasse Foo anpassen. Die meisten eigenen Metaklassen sind von type abgeleitet (siehe unten), ansonsten wird es schwierig, dass sich Foo hinterher wie eine "richtige" Klasse benimmt.

Benutzerdefinierte Metaklassen werden "vererbt", das heißt, der Typ der ersten Elternklasse wird automatisch als Metaklasse für eine abgeleitete Klasse verwendet. Im Beispiel:

   1 class Foo(object):
   2     __metaclass__ = MyMetaclass
   3 class Bar(Foo, Quux):
   4     pass

Bar wird nun so erstellt (Pseudocode):

   1 Bar = type(Foo)('Bar', (Foo, Quux), {})

Anwendungsbeispiele

Die meisten Anwendungen von Metaklassen sind recht simpel, denn sie überschreiben nur type.__new__, welches die neue Klasse erstellt. Sie führen also Aktionen beim Erstellen der Klasse aus.

Hier ein kleines Beispiel, wie man eine Methode test() zu allen Klassen mit der Metaklasse TestMeta hinzufügt:

   1 class TestMeta(type):
   2     def __new__(mcs, name, bases, dct):
   3         def test(self):
   4             return "Hallo Welt"
   5         dct['test'] = test
   6         return type.__new__(mcs, name, bases, dct)
   7 
   8 class MyClass(object):
   9     __metaclass__ = TestMeta
  10 
  11 class AnotherClass(MyClass):
  12     pass

Die beiden Klassen MyClass und AnotherClass haben nun eine Methode test, die "Hallo Welt" zurückgibt.

Mittels Metaklassen kann man auch Klassen in einer Liste registrieren:

   1 # -*- coding: utf-8 -*-
   2 
   3 class Registry(type):
   4     registry = []
   5     def __new__(mcs, name, bases, d):
   6         new_cls = type.__new__(mcs, name, bases, d)
   7         Registry.registry.append(new_cls)
   8         return new_cls
   9 
  10 class MyClass(object):
  11     __metaclass__ = Registry
  12 
  13 class AnotherClass(object):
  14     __metaclass__ = Registry

Gleich nach der Erstellung der Klassen MyClass und AnotherClass werden sie in der Liste Registry.registry auftauchen.

Metaklassen (last edited 2009-06-17 16:14:15 by localhost)