0

Lets say we have a parent class like the following

class P():
    @staticmethod
    def sth():
        pass

And I create several child classes that define the sth() method, something like the following

class P_a(P):
    @staticmethod
    def sth():
        #Implementation a

class P_b(P):
    @staticmethod
    def sth():
        #Implementation b

class P_c(P):
    @staticmethod
    def sth():
        #Implementation c

How would I call the sth() method of all the child classes?

At the moment, I'm just adding the classes to a list and, based on a for loop, calling the sth() method on all of them. Because that method is implemented in every class, all of them understand it and know if they should take care of the task or not (Not sure if this is the best way of doing this tho)

Is it there a way of basically calling the sth() method of all the classes that inherit from class P?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Manuel
  • 730
  • 7
  • 25
  • Do these have to be `@staticmethod`? If not, you could use [`__init_subclass__`](https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__) – DeepSpace Jun 08 '21 at 19:57
  • 1
    If they do have to be static, you could use a metaclass to handle the "adding the classes to a list and, based on a for loop, calling the sth() method on all of them" part for you. – DeepSpace Jun 08 '21 at 19:58
  • 1
    What are you trying to accomplish exactly? This could be an [XY problem](https://meta.stackexchange.com/q/66377/343832). – wjandrea Jun 08 '21 at 20:13
  • @wjandrea I'm trying to not need to, everytime I add a new implementation, add such implementation to a list. I think of `P` as an abstract class with the implementations being subclasses that do things different in the `sth()` method. Lets say I add an implementation "d", I would need to add that implementation to the loop that calls all the implementations, trying to avoid that if possible. – Manuel Jun 08 '21 at 22:21
  • @Manuel I get that, but I'm asking why you're doing that in the first place. Like, why do you need to call the `sth` method of each subclass? Maybe there's a better alternative. – wjandrea Jun 08 '21 at 22:24
  • @wjandrea. On the implementation, I'm getting a parameter that I don't know what it is, but I know it is either of (as of now) 5 values for example. And depending on the value I receive, `sth` needs to do things differently so, instead of doing `x` amount of `if else` instances, I send the class the parameter and the class will dictate if it handles it or not – Manuel Jun 08 '21 at 22:27
  • @Manuel I'm not following. That sounds like you're already using metaclasses, no? – wjandrea Jun 08 '21 at 22:28
  • @Manuel I just saw your edit. Maybe you could use [something like a switch statement](/q/60208/4518341) instead? – wjandrea Jun 08 '21 at 22:31
  • @wjandrea had to search the term, I think I kind of used metaclasses without knowing it. The answer by ErdoganOnal seems to be what I'm looking for. Will research more about metaclasses! – Manuel Jun 08 '21 at 22:32
  • @wjandrea the first iteration was kind of a switch statement. But using that would require adding a new clause every time a new child is added which is what I'm trying to avoid – Manuel Jun 08 '21 at 22:34

1 Answers1

2

Try this:

class P:
    subclasses = []

    def __init_subclass__(cls, *args, **kwargs) -> None:
        P.subclasses.append(cls)

    @staticmethod
    def sth():
        print("Base Implementation")

    @classmethod
    def call_all_sth(cls):
        cls.sth()
        for klass in cls.subclasses:
            klass.sth()

class P_a(P):
    @staticmethod
    def sth():
        print("Implementation a")

class P_b(P):
    @staticmethod
    def sth():
        print("Implementation b")

class P_c(P):
    @staticmethod
    def sth():
        print("Implementation c")

P.call_all_sth()

Output is:

Base Implementation
Implementation a
Implementation b
Implementation c
wjandrea
  • 28,235
  • 9
  • 60
  • 81
ErdoganOnal
  • 800
  • 6
  • 13
  • Gonna try this out!. Never used `@classmethod`. Is it sending the Class as a parameter? Similar to what the `self` would be on a method without a decorator – Manuel Jun 08 '21 at 22:24