Kurs
Eine Metaklasse in Python ist die Klasse einer Klasse und legt fest, wie sich eine Klasse verhält. Eine Klasse ist selbst eine Instanz einer Metaklasse. Eine Klasse in Python bestimmt, wie sich ihre Instanzen verhalten. Um Metaklassen wirklich zu verstehen, solltest du bereits mit Python-Klassen gearbeitet haben. Bevor wir tiefer einsteigen, räumen wir ein paar Grundbegriffe aus dem Weg.
Alles in Python ist ein Objekt
class TestClass():
pass
my_test_class = TestClass()
print(my_test_class)
<__main__.TestClass object at 0x7f6fcc6bf908>
Python-Klassen lassen sich dynamisch erzeugen
type in Python erlaubt es uns, den Typ eines Objekts zu ermitteln. Schauen wir uns den Typ des oben erzeugten Objekts an.
type(TestClass)
type
type(type)
type
Moment, was ist da passiert? Wir würden erwarten, dass der Typ des oben erstellten Objekts „class“ ist – ist er aber nicht. Behalte den Gedanken kurz im Hinterkopf, wir kommen gleich darauf zurück. Außerdem sehen wir, dass der Typ von type selbst type ist. Es ist also eine Instanz von type. Ein weiterer „magischer“ Trick von type ist, dass wir damit Klassen dynamisch erzeugen können. Unten zeigen wir, wie das geht. Die Klasse DataCamp unten ließe sich mit type wie folgt erzeugen:
class DataCamp():
pass
DataCampClass = type('DataCamp', (), {})
print(DataCampClass)
print(DataCamp())
<class '__main__.DataCamp'>
<__main__.DataCamp object at 0x7f6fcc66e358>
Im obigen Beispiel ist DataCamp der Klassenname, während DataCampClass die Variablenreferenz auf die Klasse ist. Beim Einsatz von type können wir Attribute über ein Dictionary übergeben, wie hier gezeigt:
PythonClass = type('PythonClass', (), {'start_date': 'August 2018', 'instructor': 'John Doe'} )
print(PythonClass.start_date, PythonClass.instructor)
print(PythonClass)
August 2018 John Doe
<class '__main__.PythonClass'>
Wenn unsere PythonClass von der Klasse DataCamp erben soll, übergeben wir sie als zweites Argument bei der Definition mit type:
PythonClass = type('PythonClass', (DataCamp,), {'start_date': 'August 2018', 'instructor': 'John Doe'} )
print(PythonClass)
<class '__main__.PythonClass'>
Nachdem diese zwei Konzepte geklärt sind, erkennen wir: Python erstellt Klassen mithilfe einer Metaklasse. Wir haben gesehen, dass alles in Python ein Objekt ist – und diese Objekte werden von Metaklassen erzeugt. Immer wenn wir mit class eine Klasse definieren, erzeugt im Hintergrund eine Metaklasse diese Klasse. Wir haben oben bereits gesehen, wie type das praktisch übernimmt. Das ist vergleichbar mit str für Strings und int für Ganzzahlen. In Python erlaubt uns das Attribut ___class__, den Typ der aktuellen Instanz zu prüfen. Erstellen wir unten einen String und prüfen seinen Typ.
article = 'metaclasses'
article.__class__
str
Wir können den Typ auch mit type(article) prüfen.
type(article)
str
Wenn wir den Typ von str prüfen, stellen wir ebenfalls fest, dass er type ist.
type(str)
type
Prüfen wir den Typ von float, int, list, tuple und dict, erhalten wir ein ähnliches Ergebnis. Das liegt daran, dass all diese Objekte vom Typ type sind.
print(type(list),type(float), type(dict), type(tuple))
<class 'type'> <class 'type'> <class 'type'> <class 'type'>
Wir haben bereits gesehen, dass type Klassen erzeugt. Wenn wir also __class__ von __class__ prüfen, sollte type zurückgegeben werden.
article.__class__.__class__
type
Meistere deine Datenkenntnisse mit DataCamp
Mehr als 10 Millionen Menschen lernen Python, R, SQL und andere technische Fertigkeiten in unseren praxisorientierten Kursen, die von Branchenexperten entwickelt wurden.

Eigene Metaklassen erstellen
In Python können wir den Prozess der Klassenerzeugung anpassen, indem wir das Schlüsselwort metaclass in der Klassendefinition verwenden. Das funktioniert auch, indem wir von einer Klasse erben, die dieses Schlüsselwort bereits gesetzt hat.
class MyMeta(type):
pass
class MyClass(metaclass=MyMeta):
pass
class MySubclass(MyClass):
pass
Unten sehen wir, dass der Typ der Klasse MyMeta type ist und dass der Typ von MyClass und MySubClass MyMeta ist.
print(type(MyMeta))
print(type(MyClass))
print(type(MySubclass))
<class 'type'>
<class '__main__.MyMeta'>
<class '__main__.MyMeta'>
Wird eine Klasse ohne Metaklasse definiert, verwendet Python standardmäßig die Metaklasse type. Wenn eine Metaklasse angegeben ist und sie keine Instanz von type() ist, wird sie direkt als Metaklasse verwendet.
__new__ und __init__
Metaklassen können auf zwei Arten wie unten gezeigt definiert werden. Den Unterschied erklären wir im Anschluss.
class MetaOne(type):
def __new__(cls, name, bases, dict):
pass
class MetaTwo(type):
def __init__(self, name, bases, dict):
pass
__new__ wird genutzt, wenn man dict oder das bases-Tuple festlegen möchte, bevor die Klasse erzeugt wird. Der Rückgabewert von __new__ ist üblicherweise eine Instanz von cls. __new__ erlaubt Unterklassen unveränderlicher Typen, die Instanzerzeugung anzupassen. In benutzerdefinierten Metaklassen kann es überschrieben werden, um die Klassenerzeugung zu steuern. __init__ wird in der Regel aufgerufen, nachdem das Objekt erstellt wurde, um es zu initialisieren.
Metaklassen-Methode __call__
Laut der offiziellen Dokumentation können wir auch andere Klassenmethoden überschreiben, indem wir in der Metaklasse eine eigene __call__()-Methode definieren, die benutzerdefiniertes Verhalten beim Aufruf der Klasse ermöglicht.
Metaklassen-Methode __prepare__
Nach Pythons Data-Model-Dokumentation
Sobald die passende Metaklasse ermittelt wurde, wird der Klassen-Namespace vorbereitet. Wenn die Metaklasse ein Attribut __prepare__ hat, wird es wie folgt aufgerufen: namespace = metaclass.__prepare__(name, bases, **kwds) (weitere Schlüsselwortargumente stammen aus der Klassendefinition). Hat die Metaklasse kein __prepare__-Attribut, wird der Klassen-Namespace als leeres geordnetes Mapping initialisiert. - docs.python.org
Singleton-Pattern mit einer Metaklasse
Dieses Entwurfsmuster beschränkt die Instanziierung einer Klasse auf genau ein Objekt. Das ist zum Beispiel nützlich, wenn du eine Klasse für die Datenbankverbindung entwickelst und nur eine einzige Instanz dieser Verbindungsklasse haben möchtest.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonMeta,cls).__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonClass(metaclass=SingletonMeta):
pass
Fazit
In diesem Artikel hast du gelernt, was Metaklassen sind und wie wir sie in Python einsetzen können. Metaklassen lassen sich unter anderem für Logging, die Registrierung von Klassen zur Erzeugungszeit oder für Profiling nutzen. Sie wirken recht abstrakt, und vielleicht fragst du dich, ob du sie überhaupt brauchst. Python-Veteran Tim Peters beantwortet das am treffendsten.
"Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don’t (the people who actually need them know with certainty that they need them, and don’t need an explanation about why).” - realpython
Wenn du mehr über Python lernen möchtest, starte den Python Programming-Lernpfad von DataCamp und lies unser Python Classes Tutorial.