Metaklassen I

Seit Python 2.2 gibt es keinen Unterschied mehr zwischen zwischen Typen und Klassen, wenn diese von object abgeleitet sind. Die, die es nicht sind, werden alte Klassen (classic classes) genannt. Ich persönlich verwende nur noch neue Klassen (new style classes), da diese einige Vorteile gegenüber dem alten Modell bieten. In der Standard-Bibliothek und in vielen anderen Modulen werden aber aus Kompatibilitätsgründen, Bequemlichkeit oder Unwissenheit meist die alten benutzt. (Default, wenn nicht object zu den Basisklassen gehört.) Mit den genauen Unterschieden zwischen alten und neuen Klassen wird sich aber wahrscheinlich ein anderer Blog-Eintrag beschäftigen.

Vor Python 2.2 war type nur eine eingebaute Funktion, die den Typ eines Objekts zurückgegeben hat:

>>> type("")
<type 'str'>
>>> type(1)
<type 'int'>
>>> type(1) is int
True

Da der Unterschied zwischen Funktionen und Klassen in Python nicht so groß ist, funktioniert dies immer noch, type ist nun aber auch eine Klasse, und zwar diejenige, von der alle neuen Klassen sind. Da type selber eine neue Klasse ist, ist type die einzige Klasse, die gleichzeitig ihre eigene Instanz ist:

>>> isinstance(type, type)
True

Wem das nicht verwirrend genug ist, der mag sich über Beziehung von object zu type den Kopf zerbrechen, die hier nicht so wichtig ist:

>>> isinstance(type, object)
True
>>> isinstance(object, type)
True
>>> issubclass(type, object)
True
>>> issubclass(object, type)
False

Es gab mal ein Dokument, das auf diesen Aspekt näher einging und das auch mit hübschen Ascii-Graphiken illustrierte. Leider finde ich den Link dazu nicht mehr.

Um ein neues type-Objekt (eine Klasse) zu erzeugen, kann man type mit drei Argumenten aufrufen: dem Namen der neuen Klasse, dem Tupel der Basisklassen und dem dict-Objekt (Dictionary) der Basisklassen:

>>> type("Test", (), {})
<class '__main__.Test'>

object wird automatisch zu den Basisklassen hinzugefügt, wenn es nicht schon implizit (als Basisklasse einer der Basen) oder explizit als Basis aufgelistet ist. Das Definieren einer Klasse mit einem class-Block ist tatsächlich nur eine syntaktisch schönere Form für so einen Aufruf.

Nun, da klar ist, dass das Erzeugen einer neuen Klasse gleich dem Instanziieren von type (bzw. classobj für alte Klassen) ist, ist zu erwarten, dass man Unterklassen von type erzeugen kann und neue Klassen als Instanzen dieser. Dies ist tatsächlich der Fall. Diese Unterklassen von type heißen Metaklassen (Klassen von Klassen, Klassenklassen). Um herauszufinden von welchem Typ eine neue Klasse sein soll, geht Python den folgenden Weg:

  • Gibt es eine Variable __metaclass__ im Klassenkontext, wird diese genommen.
  • Gibt es Basisklasse, die eine neue Klasse ist, wird deren Klasse genommen.
  • Gibt es nur alte Basisklassen wird classobj (alte Klasse) genommen.
  • Wenn es eine globale Variable __metaclass__ gibt, wird diese genommen.
  • Andernfalls wird classobj genommen.

Der letzte Punkt ist etwas schade, wird sich aber aus Kompatibilitätsgründen erst in Python 3000 ändern. Dadurch sind die meisten Klassen, denen man normalerweise begegnet, alte Klassen (s.o.).