How to automatically create all child objects of a parent class in python?

Viewed 537

I want to automate the creation of objects for all child classes of a parent class.For example: This is the parent class

from abc import ABC,abstractmethod
class Parent(ABC):
    @abstractmethod
    def fetch(self):
        # some code here

Now I create child classes for this parent class

#child classes
class obj1(Parent):
    def fetch(self):
       # some code

class obj2(Parent):
    def fetch(self):
       # some code

class obj3(Parent):
    def fetch(self):
       # some code

Now my problem is I want to create one object for all these children classed here automatically and save them in an objectList.So that even if someone creates a new child class later, the code will automatically create an object for that new child class and append it in the objectList.

I can do this manually by:

objectList = []
objectList.append(obj1())
objectList.append(obj2())
objectList.append(obj3())

But if someone creates a new child for example obj4() I have to manually append obj4. How to create an object of all child classes automatically?

2 Answers

In python3, subclasses are registered automatically, and made available via the __subclasses__ method:

objectList = [cls() for cls in Parent.__subclasses__()]

Could also use a Metaclass, although then you end up with all the classes in your list, including Parent:

class MetaParent(type):
  subclasses = []
  def __new__(cls, name, bases, kwargs):
    kls = super().__new__(cls, name, bases, kwargs)
    cls.subclasses.append(kls())
    return kls

class Parent(metaclass=MetaParent):
  pass

class ChildA(Parent):
  pass

class ChildB(Parent):
  pass

Now MetaParent.subclasses will have all your instances. Filter out instances of Parent if you want: [cls for cls in MetaParent.subclasses if not type(Parent) == cls]

As an alternative to metaclasses, you could use __init_subclass__, which gets called whenever a class is subclassed.

from abc import ABC,abstractmethod

object_list = []
class Parent(ABC):
    @abstractmethod
    def fetch(self):
        # some code here
        pass
    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        object_list.append(cls())

Note, it is a special-case class method, i.e., it gets the class as the first argument.

Of course, this depends on you knowing how these classes are meant to be instantiated (here with no arguments).

In the repl:

In [3]: #child classes
   ...: class obj1(Parent):
   ...:     def fetch(self):
   ...:        # some code
   ...:        pass
   ...:
   ...: class obj2(Parent):
   ...:     def fetch(self):
   ...:        # some code
   ...:        pass
   ...:
   ...: class obj3(Parent):
   ...:     def fetch(self):
   ...:        # some code
   ...:        pass
   ...:

In [4]: object_list
Out[4]:
[<__main__.obj1 at 0x7fd233c23990>,
 <__main__.obj2 at 0x7fd233c23050>,
 <__main__.obj3 at 0x7fd233c23650>]
Related