How to run code when a class is subclassed?
inheritance, python
Solution
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
Problem
Is there a way to trigger code when my class is subclassed? ``` class SuperClass: def triggered_routine(subclass): print("was subclassed by " + subclass.__name__) magically_register_triggered_routine() print("foo") class SubClass0(SuperClass): pass print("bar") class SubClass1(SuperClass): print("test") ``` Should output ``` foo was subclassed by SubClass0 bar test was subclassed by SubClass1 ```