Here's a version without recursion:
def get_subclasses_gen(cls):
def _subclasses(classes, seen):
while True:
subclasses = sum((x.__subclasses__() for x in classes), [])
yield from classes
yield from seen
found = []
if not subclasses:
return
classes = subclasses
seen = found
return _subclasses([cls], [])
This differs from other implementations in that it returns the original class. This is because it makes the code simpler and:
class Ham(object):
pass
assert(issubclass(Ham, Ham)) # True
If get_subclasses_gen looks a bit weird that's because it was created by converting a tail-recursive implementation into a looping generator:
def get_subclasses(cls):
def _subclasses(classes, seen):
subclasses = sum(*(frozenset(x.__subclasses__()) for x in classes))
found = classes + seen
if not subclasses:
return found
return _subclasses(subclasses, found)
return _subclasses([cls], [])