In Python, given a module X and a class Y, how can I iterate or generate a list of all subclasses of Y that exist in module X?
Asked
Active
Viewed 1.2k times
4 Answers
25
Although Quamrana's suggestion works fine, there are a couple of possible improvements I'd like to suggest to make it more pythonic. They rely on using the inspect module from the standard library.
- You can avoid the getattr call by using
inspect.getmembers()
- The try/catch can be avoided by using
inspect.isclass()
With those, you can reduce the whole thing to a single list comprehension if you like:
def find_subclasses(module, clazz):
return [
cls
for name, cls in inspect.getmembers(module)
if inspect.isclass(cls) and issubclass(cls, clazz)
]

runeh
- 3,771
- 1
- 21
- 16
-
Works great, but my response also returns the base class (the one I send in with clazz), any idea? – fredrik Feb 12 '10 at 14:55
-
Fredrik, turns out issubclass(Foo, Foo) is True. Easy fix though. add "and not cls is clazz" to the list comprehension – runeh Mar 19 '10 at 23:32
-
2-1: code doesn't work. correct it'd be: `cls for name, cls in inspect.getmembers(module)` – tback Dec 17 '10 at 14:58
15
Here's one way to do it:
import inspect
def get_subclasses(mod, cls):
"""Yield the classes in module ``mod`` that inherit from ``cls``"""
for name, obj in inspect.getmembers(mod):
if hasattr(obj, "__bases__") and cls in obj.__bases__:
yield obj

Chris AtLee
- 7,798
- 3
- 28
- 27
-
My solution won't return classes that are not direct descendants of 'cls'. quamrana's solution below will find any class that has 'cls' somewhere in its ancestry. – Chris AtLee Sep 15 '08 at 15:41
5
Can I suggest that neither of the answers from Chris AtLee and zacherates fulfill the requirements? I think this modification to zacerates answer is better:
def find_subclasses(module, clazz):
for name in dir(module):
o = getattr(module, name)
try:
if (o != clazz) and issubclass(o, clazz):
yield name, o
except TypeError: pass
The reason I disagree with the given answers is that the first does not produce classes that are a distant subclass of the given class, and the second includes the given class.

quamrana
- 37,849
- 12
- 53
- 71
1
Given the module foo.py
class foo(object): pass
class bar(foo): pass
class baz(foo): pass
class grar(Exception): pass
def find_subclasses(module, clazz):
for name in dir(module):
o = getattr(module, name)
try:
if issubclass(o, clazz):
yield name, o
except TypeError: pass
>>> import foo
>>> list(foo.find_subclasses(foo, foo.foo))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>)]
>>> list(foo.find_subclasses(foo, object))
[('bar', <class 'foo.bar'>), ('baz', <class 'foo.baz'>), ('foo', <class 'foo.foo'>), ('grar', <class 'foo.grar'>)]
>>> list(foo.find_subclasses(foo, Exception))
[('grar', <class 'foo.grar'>)]

Aaron Maenpaa
- 119,832
- 11
- 95
- 108