How to run code when a class is subclassed?

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

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

From: stackoverflow.com/q/18126552

Back to homepage or read more recommendations: