Python Language
Metaklassen
Suche…
Einführung
Metaclasses können Sie das Verhalten von Python - Klassen zu tief ändern (in Bezug darauf, wie sie definiert sind, instanziiert, zugegriffen wird , und mehr) von dem Ersatz - type
Metaklasse , die neuen Klassen standardmäßig verwenden.
Bemerkungen
Berücksichtigen Sie beim Entwerfen Ihrer Architektur, dass viele Dinge, die mit Metaklassen erreicht werden können, auch mit einfacheren Semantiken erreicht werden können:
- Traditionelles Erbe ist oft mehr als genug.
- Klassendekorateure können Funktionalität auf Ad-hoc-Weise in Klassen einmischen.
- Python 3.6 führt
__init_subclass__()
, mit der eine Klasse an der Erstellung ihrer Unterklasse teilnehmen kann.
Grundlegende Metaklassen
Wenn type
mit drei Argumenten aufgerufen wird, verhält es sich wie die (Meta-) Klasse und erstellt eine neue Instanz, d. H. es erzeugt eine neue Klasse / einen neuen Typ.
Dummy = type('OtherDummy', (), dict(x=1))
Dummy.__class__ # <type 'type'>
Dummy().__class__.__class__ # <type 'type'>
Es ist möglich, eine Unterklasse type
eine benutzerdefinierte metaclass zu erstellen.
class mytype(type):
def __init__(cls, name, bases, dict):
# call the base initializer
type.__init__(cls, name, bases, dict)
# perform custom initialization...
cls.__custom_attribute__ = 2
Jetzt haben wir eine neue benutzerdefinierte mytype
Metaklasse, mit der Klassen auf dieselbe Weise wie type
.
MyDummy = mytype('MyDummy', (), dict(x=2))
MyDummy.__class__ # <class '__main__.mytype'>
MyDummy().__class__.__class__ # <class '__main__.mytype'>
MyDummy.__custom_attribute__ # 2
Wenn wir mit dem Schlüsselwort class
eine neue Klasse erstellen, wird die Metaklasse standardmäßig auf Basis der Basisklassen ausgewählt.
>>> class Foo(object):
... pass
>>> type(Foo)
type
Im obigen Beispiel ist die einzige Basenklasse object
also ist unsere Metaklasse der object
, also type
. Es ist möglich, den Standard zu überschreiben, es hängt jedoch davon ab, ob wir Python 2 oder Python 3 verwenden:
Ein spezielles Klassenebenenattribut __metaclass__
kann verwendet werden, um die Metaklasse anzugeben.
class MyDummy(object):
__metaclass__ = mytype
type(MyDummy) # <class '__main__.mytype'>
Ein spezielles Schlüsselwort für eine metaclass
die Metaklasse an.
class MyDummy(metaclass=mytype):
pass
type(MyDummy) # <class '__main__.mytype'>
Alle Schlüsselwortargumente (außer metaclass
) in der Klassendeklaration werden an die Metaklasse übergeben. Daher gibt die class MyDummy(metaclass=mytype, x=2)
x=2
als Schlüsselwortargument an den mytype
Konstruktor weiter.
Lesen Sie diese ausführliche Beschreibung der Python-Metaklassen für weitere Details.
Singletons mit Metaklassen
Ein Singleton ist ein Muster, das die Instantiierung einer Klasse auf eine Instanz / ein Objekt beschränkt. Weitere Informationen zu Python-Singleton-Entwurfsmustern finden Sie hier .
class SingletonType(type):
def __call__(cls, *args, **kwargs):
try:
return cls.__instance
except AttributeError:
cls.__instance = super(SingletonType, cls).__call__(*args, **kwargs)
return cls.__instance
class MySingleton(object):
__metaclass__ = SingletonType
class MySingleton(metaclass=SingletonType):
pass
MySingleton() is MySingleton() # True, only one instantiation occurs
Verwenden einer Metaklasse
Metaklassensyntax
class MyClass(object):
__metaclass__ = SomeMetaclass
class MyClass(metaclass=SomeMetaclass):
pass
Python 2 und 3 Kompatibilität mit six
import six
class MyClass(six.with_metaclass(SomeMetaclass)):
pass
Benutzerdefinierte Funktionalität mit Metaklassen
Die Funktionalität in Metaklassen kann so geändert werden, dass beim Erstellen einer Klasse eine Zeichenfolge in die Standardausgabe gedruckt wird oder eine Ausnahme ausgelöst wird. Diese Metaklasse gibt den Namen der zu erstellenden Klasse aus.
class VerboseMetaclass(type):
def __new__(cls, class_name, class_parents, class_dict):
print("Creating class ", class_name)
new_class = super().__new__(cls, class_name, class_parents, class_dict)
return new_class
Sie können die Metaklasse wie folgt verwenden:
class Spam(metaclass=VerboseMetaclass):
def eggs(self):
print("[insert example string here]")
s = Spam()
s.eggs()
Die Standardausgabe wird sein:
Creating class Spam
[insert example string here]
Einführung in Metaklassen
Was ist eine Metaklasse?
In Python ist alles ein Objekt: Ganzzahlen, Strings, Listen, sogar Funktionen und Klassen selbst sind Objekte. Und jedes Objekt ist eine Instanz einer Klasse.
Um die Klasse eines Objekts x zu überprüfen, kann type(x)
aufgerufen werden.
>>> type(5)
<type 'int'>
>>> type(str)
<type 'type'>
>>> type([1, 2, 3])
<type 'list'>
>>> class C(object):
... pass
...
>>> type(C)
<type 'type'>
Die meisten Klassen in Python sind Instanzen des type
. type
selbst ist auch eine Klasse. Solche Klassen, deren Instanzen auch Klassen sind, werden Metaklassen genannt.
Die einfachste Metaclass
OK, also gibt es in Python bereits eine Metaklasse: type
. Können wir noch einen schaffen?
class SimplestMetaclass(type):
pass
class MyClass(object):
__metaclass__ = SimplestMetaclass
Das fügt keine Funktionalität hinzu, aber es ist eine neue Metaklasse. Sehen Sie, dass MyClass jetzt eine Instanz von SimplestMetaclass ist:
>>> type(MyClass)
<class '__main__.SimplestMetaclass'>
Eine Metaklasse, die etwas tut
Eine Metaklasse, die etwas tut, überschreibt normalerweise __new__
type
, um einige Eigenschaften der zu erstellenden Klasse zu ändern, bevor das ursprüngliche __new__
, das die Klasse erstellt:
class AnotherMetaclass(type):
def __new__(cls, name, parents, dct):
# cls is this class
# name is the name of the class to be created
# parents is the list of the class's parent classes
# dct is the list of class's attributes (methods, static variables)
# here all of the attributes can be modified before creating the class, e.g.
dct['x'] = 8 # now the class will have a static variable x = 8
# return value is the new class. super will take care of that
return super(AnotherMetaclass, cls).__new__(cls, name, parents, dct)
Die Standard-Metaklasse
Sie haben vielleicht gehört, dass alles in Python ein Objekt ist. Es stimmt, und alle Objekte haben eine Klasse:
>>> type(1)
int
Das Literal 1 ist eine Instanz von int
. Lass uns eine Klasse deklarieren:
>>> class Foo(object):
... pass
...
Jetzt können wir es instanziieren:
>>> bar = Foo()
Was ist die Klasse der bar
?
>>> type(bar)
Foo
Schön, bar
ist ein Beispiel für Foo
. Aber was ist die Klasse von Foo
selbst?
>>> type(Foo)
type
Ok, Foo
selbst ist eine Instanz des type
. Wie wäre es mit dem type
selbst?
>>> type(type)
type
Was ist also eine Metaklasse? Lassen Sie uns jetzt so tun, als wäre es nur ein schicker Name für die Klasse einer Klasse. Zum Mitnehmen:
- Alles ist ein Objekt in Python, also hat alles eine Klasse
- Die Klasse einer Klasse wird als Metaklasse bezeichnet
- Die Standard-Metaklasse ist
type
und bei weitem die häufigste Metaklasse
Aber warum sollten Sie sich mit Metaklassen auskennen? Nun, Python selbst ist ziemlich "hackbar", und das Konzept der Metaklasse ist wichtig, wenn Sie fortgeschrittene Dinge wie Meta-Programmierung machen oder die Initialisierung Ihrer Klassen kontrollieren möchten.