Klassen (Standard) sind Instanzen von type
. So wie eine Instanz einer Klasse Foo
von foo = Foo(...)
, erstellt wird, wird eine Instanz type
(d. H. Eine Klasse) von myclass = type(name, bases, clsdict)
erstellt.
Wenn Sie möchten, dass im Moment der Klassenerstellung etwas Besonderes passiert, dann müssen Sie das, was die Klasse erzeugt, ändern - also type
. Der Weg, dies zu tun, besteht darin, eine Unterklasse von type
zu definieren - d. H. Eine Metaklasse.
Eine Metaklasse ist zu ihrer Klasse wie eine Klasse zu ihrer Instanz.
In Python2 würden Sie die Metaklasse einer Klasse definieren mit
class SuperClass:
__metaclass__ = Watcher
wo Watcher
eine Unterklasse von type
ist.
In Python3 die Syntax
class SuperClass(metaclass=Watcher)
Beide
Superclass = Watcher(name, bases, clsdict)
, wo in diesem Fall zu
äquivalent sind geändert worden ist, die Zeichenfolge
name
'Superclass'
entspricht, und ist das Tupel
bases
(object,)
. Das
clsdict
ist ein Wörterbuch der Klassenattribute, die im Hauptteil der Klassendefinition definiert sind.
Beachten Sie die Ähnlichkeit zu myclass = type(name, bases, clsdict)
.
So, wie Sie __init__
eine Klasse verwenden würden Ereignisse im Moment einer Schöpfung der Instanz zu steuern, können Sie Ereignisse zur Zeit einer Schöpfung der Klasse Steuerung mit einer Metaklasse der __init__
:
class Watcher(type):
def __init__(cls, name, bases, clsdict):
if len(cls.mro()) > 2:
print("was subclassed by " + name)
super(Watcher, cls).__init__(name, bases, clsdict)
class SuperClass:
__metaclass__ = Watcher
print("foo")
class SubClass0(SuperClass):
pass
print("bar")
class SubClass1(SuperClass):
print("test")
druckt
foo
was subclassed by SubClass0
bar
test
was subclassed by SubClass1
Verwenden Sie eine Metaklasse; Metaklassen werden beim Erstellen von Klassen aufgerufen, genauso wie Klassen beim Erstellen von Instanzen aufgerufen werden. –
Kann keine Antwort hinzufügen, aber python3.6 hat heute die '__init_subclass__' - check it out! –
@OrDuan: Danke, klingt nützlich. Vielleicht sogar Grund genug, um diese Frage ein Duplikat zu markieren, da es jetzt eine dedizierte Lösung für mein Problem statt der "Verwendung einer Metaklasse" gibt. –