Python: Show all subclasses of a class

Just a lovely scroll.

Update (2024-08-02): Updated recursive_subclasses() to deduplicate with a set.

Update (2026-06-05): Updated recursive_subclasses() to deduplicate when a class is inherited from directly as well as via a subclass, changing the approach to an iterative one using a deque on the way.

class.__subclasses__() returns a list of the direct subclasses of a given class:

In [1]: class Base: pass
   ...: class Alpha(Base): pass

In [2]: Base.__subclasses__()
Out[2]: [__main__.Alpha]

This function picks up subclasses wherever they are defined. That can make it useful for tracking down code to edit, as I showed recently.

But __subclasses__() does not descend the inheritance hierarchy, so it does not return subclasses of subclasses:

In [1]: class Base: pass
   ...: class Alpha(Base): pass
   ...: class Beta(Alpha): pass

In [2]: Base.__subclasses__()
Out[2]: [__main__.Alpha]

To get all subclasses, use this wrapper:

from collections import deque


def recursive_subclasses(klass):
    """
    Yield all subclasses of the given class, per:
    https://adamj.eu/tech/2024/05/10/python-all-subclasses/
    """
    queue = deque(klass.__subclasses__())
    seen = set()
    while queue:
        subclass = queue.popleft()
        if subclass not in seen:
            seen.add(subclass)
            yield subclass
            queue.extend(subclass.__subclasses__())

It yields all subclasses and then recursively from their subclasses. It uses a set, seen, to avoid duplicates, which can arise from patterns like diamond-style inheritance.

For example:

In [4]: list(recursive_subclasses(Base))
Out[4]: [__main__.Alpha, __main__.Beta]

As recursive_subclasses() is a generator function, list() is required to get all the classes at once.

Fin

Stay classy,

—Adam


Read my book Boost Your Django DX, freshly updated in November 2024.


Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: