Classes (by default) are instances of type. Just as an instance of a class Foo is created by foo = Foo(...), an instance of type (i.e. a class) is created by myclass = type(name, bases, clsdict).
If you want something special to happen at the moment of class-creation, then you have to modify the thing creating the class -- i.e. type. The way to do that is to define a subclass of type -- i.e. a metaclass.
A metaclass is to its class as a class is to its instance.
In Python2 you would define the metaclass of a class with
class SuperClass: __metaclass__ = Watcher
where Watcher is a subclass of type.
In Python3 the syntax has been changed to
class SuperClass(metaclass=Watcher)
Both are equivalent to
Superclass = Watcher(name, bases, clsdict)
where in this case, name equals the string 'Superclass', and bases is the tuple (object, ). The clsdict is a dictionary of the class attributes defined in the body of the class definition.
Note the similarity to myclass = type(name, bases, clsdict).
So, just as you would use a class's __init__ to control events at the moment of a instance's creation, you can control events at the moment of a class's creation with a metaclass's __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")
prints
foo was subclassed by SubClass0 bar test was subclassed by SubClass1
__init_subclass__- check it out!