I'm writing a small Python application that contains a few nested classes, like the example below:
class SuperBar(object):
pass
class Foo(object):
NAME = 'this is foo'
class Bar(SuperBar):
MSG = 'this is how Bar handle stuff'
class AnotherBar(SuperBar):
MSG = 'this is how Another Bar handle stuff'
I'm using nested classes to create some sort of hierarchy and to provide a clean way to implement features for a parser.
At some point, I want to create a list of the inner classes. I'd like to have the following output:
[<class '__main__.Bar'>, <class '__main__.AnotherBar'>]
The question is: What is the recommended method to get a list of inner classes in a pythonic way?
I managed to get a list of inner class objects with the method below:
import inspect
def inner_classes_list(cls):
return [cls_attribute for cls_attribute in cls.__dict__.values()
if inspect.isclass(cls_attribute)
and issubclass(cls_attribute, SuperBar)]
It works, but I'm not sure if using __dict__
directly is a good thing to do. I'm using it because it contains the actual class
instances that I need and seems to be portable across Python 2 and 3.
First: I can't see how nested classes can be of any use for you. Once you have an instance f
of Foo
, do you realize that f.Bar
and f.AnotherBar
will be the same object for all instances? That is - you can't record any attribute specific from f
on f.Bar
, like f.Bar.speed
- or it will collide with an attribute from another instance g.Bar.speed
.
To overcome this, and actually, the only thing that makes sense, you'd need to have instances of Bar
and AnotherBar
attached to the instance f
. These instances usually can't be declared on the class body - you have to create them on your Foo's __init__
method.
The only thing that Bar and AntherBar can do doing there is: (1) to have a lot of class and static methods, then they work as namespaces only.
Or, if a metaclass for SuperBar
or themselves implement the descriptor protocol - https://docs.python.org/3/reference/datamodel.html#implementing-descriptors - but them, you'd be much better if superbar
itself would implement the descriptor prootocol (by having either __get__
or __set__
methods), and attached to Foo's body you'd have instances of these classes, not the classes themselves.
That said, you came with the solution of using __dict__
to getting the inner classes: that won't work if Foo
itself inherit from other classes that also have nested classes. The Superclasses of Foo
are never searched. You can have a method to either look on all classes on Foo's __mro__
, or simply use dir
and issubclass
:
class Foo:
@classmethod
def inner_classes_list(cls):
results = []
for attrname in dir(cls):
obj = getattr(cls, attrname)
if isinstance(obj, type) and issubclass(obj, SuperBar):
results.append(obj)
return results
(If you want this to work to all classes like Foo that does not share a common base, the same code will work if it is nto declared as a class method, of course - and also, SuperBar
can be a parameter to this function, if you have more than one nested-class hierarchy.)
Now you have this, we urge you to ask other questions saying what do you want to actually do - and to read about "descriptors" - and even "properties". Really: there is very little use one can think of to nested subclasses.