Python __subclasses__ hook

Category: programming


As learning of Python goes deeper and deeper, more and more special hooks are being discovered and I realize that quite some tasks could be done in different ways.

So someday I was trying to achieve a simple factory pattern. For that to happen, I need to register subclasses and dispatch accordingly. So previously I would just use a simple decorator to register a class when imported. And the basic skeleton goes like this:

g_registry = {}
def register_cls(entry_name):
    def inner(cls):
        g_registry[entry_name] = cls
        return cls
    return inner


def get_handler(name):
    return g_registry.get(name)

class Base(object):
    pass


@register_cls('A')
class ClsA(Base):
    pass


@register_cls('B')
class ClsB(Base):
    pass

Certainly this just works fine, and generally we are just OK with having a global g_registry(In fact we can further improve this for sure and remove global variable). But that day I was just browsing online and find some introduction to subclasses hook in Python. So I read on and found it very interesting in solving this registration problem. Now the registration could simply to omitted.

def get_handler(name):
    for cls in Base.__subclasses__():
        if cls.entry_name == name:
            return cls
    return None

class Base(object):
    pass


class ClsA(Base):
    entry_name = 'A'


class ClsB(Base):
    entry_name = 'B'

So you can see the code is much shorter and clearer now.

After searching, I found that there is much resources related to subclasses hook. So I did a simple experiment myself.

# test1.py
class Base(object):
    pass

class A(Base):
    pass

# test2.py
from test1 import Base
class B(Base):
    pass

# main.py
import test1
print(test1.Base.__subclasses__())
import test2
print(test1.Base.__subclasses__())

According to explanation from Tim Peters, this is implemented to reduce searches for MRO. So it is more like a compromise and therefore there is not much documentation around. However, this is indeed handy at times.

References:

  1. SO question
  2. Mailing list