Hi!
I need a working approach of getting all classes that are inherited from the base class in Python.
Thanks.
Hi!
I need a working approach of getting all classes that are inherited from the base class in Python.
Thanks.
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:
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
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__
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']
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'>}