tags:

views:

118

answers:

3

Hi!

I need a working approach of getting all classes that are inherited from the base class in Python.

Thanks.

+1  A: 

It helps if you explain why you need something like this in stead of just what you need. I can think of two use-cases:

  1. You are implementing some sort of class browser. I think most IDE systems implement this by scanning/parsing classes directly themself within a project. You could have a look at how, for example, Eric implements this

  2. You are building some sort of framework where this hierarchy is somehow important. You could consider registering your classes in a registry and have this registry scan through through the registered classes and their __bases__

Ivo van der Wijk
I am trying to implement a testing infrastructure and I want to add tests by adding test modules to a directory. Each test should be represented by a class.
Roman Prykhodchenko
you could look how py.test collects its tests.
Ivo van der Wijk
+6  A: 

New-style classes have a __subclasses__ method which returns the subclasses:

class Foo(object): pass
class Bar(Foo): pass
class Baz(Foo): pass
class Bing(Bar): pass

Here are the names of the subclasses:

print([cls.__name__ for cls in vars()['Foo'].__subclasses__()])
# ['Bar', 'Baz']

Here are the subclasses themselves:

print([cls for cls in vars()['Foo'].__subclasses__()])
# [<class '__main__.Bar'>, <class '__main__.Baz'>]

Confirmation that the subclasses do indeed list Foo as their base:

for cls in vars()['Foo'].__subclasses__():
    print(cls.__base__)
# <class '__main__.Foo'>
# <class '__main__.Foo'>

Note if you want subsubclasses, you'll have to recurse:

print([cls.__name__ for cls in vars()['Bar'].__subclasses__()])
# ['Bing']
unutbu
+1  A: 

This isn't a good answer given the much better built-in __subclasses__ which @unutbu mentions, but I present it as an exercise. The subclasses() function defined returns the dictionary created which maps all the subclass names to the subclasses themselves.

def traced_subclass(baseclass):
    class _SubclassTracer(type):
        def __new__(cls, classname, bases, classdict):
            obj = type(classname, bases, classdict)
            if baseclass in bases: # sanity check
                attrname = '_%s__derived' % baseclass.__name__
                derived = getattr(baseclass, attrname, {})
                derived.update( {classname:obj} )
                setattr(baseclass, attrname, derived)
             return obj
    return _SubclassTracer

def subclasses(baseclass):
    attrname = '_%s__derived' % baseclass.__name__
    return getattr(baseclass, attrname, None)

class BaseClass(object):
    pass

class SubclassA(BaseClass):
    __metaclass__ = traced_subclass(BaseClass)

class SubclassB(BaseClass):
    __metaclass__ = traced_subclass(BaseClass)

print subclasses(BaseClass)
# {'SubclassB': <class '__main__.SubclassB'>, 'SubclassA': <class '__main__.SubclassA'>}
martineau