Python: Show all subclasses of a class

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.
😸😸😸 Check out my new book on using GitHub effectively, Boost Your GitHub DX! 😸😸😸
One summary email a week, no spam, I pinky promise.
Related posts:
- Python: Make line number paths with
inspect - Python: unittest’s new context methods from Python 3.11 (with backports)
- Django: Pinpoint upstream changes with Git
Tags: python