Home > Back-end >  Find out overridden method in parent
Find out overridden method in parent

Time:07-06

I am familiar with OOP, and understand we can inherit from a base class and extend user_call_api in a child class adding more definitions to it. But I'm wondering is there a way that in parent class, we could find out

  • which methods are overridden (by child classes)
  • the name of (child) classes that have overridden the method
class Parent:

    def call_api(self):
        print("API is called")

    def use_call_api(self):
        # if it's overridden, find out in parent,
        # do something and then
        self.call_api()

        # if it's not overridden
        self.call_api()


class Child(Parent):

    def call_api(self):
        print("call_api")


class Child2(Parent):

    def call_api(self):
        print("call_api2")


class Child3(Parent):

    def call_api(self):
        print("call_ap3")

    def use_call_api(self):
        print("custom call_api")

CodePudding user response:

You can have a metaclass that will override the __new__ dunder-method and hold the necessary information (method name and class names that overrides it) into the singleton property of it.

import re


class Inspect(type):
    implementations = {}

    def __new__(mcs, cls, args, kwargs):
        for attr in kwargs.keys():
            if not re.match(r"^__\w __$", attr):
                mcs.implementations[attr] = (*mcs.implementations.get(attr, ()), cls)
        return type(cls, args, kwargs)

The classes (primarily the child classes inherited from Parent) should use Inspect metaclass.

The Inspect.implementations will be in their final state after the application starts and all classes and functions are declared in dynamic memory to be ready to execute the script. So you can get declare an additional method in the Parent to get the list of classes that override the current method or even was the method overridden or not.

import inspect


class Parent:

    @staticmethod
    def overridden() -> tuple:
        return Inspect.implementations.get(inspect.stack()[1].function, ())

    def call_api(self):
        print("API is called")

    def use_call_api(self):
        # if it's overridden, find out in parent,
        if self.overridden():
            print("use_call_api has been overridden in", self.overridden())

            # do something and then
            self.call_api()

        # if it's not overridden
        self.call_api()


class Child(Parent, metaclass=Inspect):

    def call_api(self):
        print("call_api")

    def use_call_api(self):
        pass


if __name__ == "__main__":
    p = Parent()
    p.use_call_api()

If you run the above code, then you will see that when Child overrides use_call_api method, then the overridden method called by the same method of the Parent will contain the Child, indicating that it overrides the method. If we do not implement use_call_api for Child, the overridden would return an empty tuple, and if self.overridden() condition would not work and will pass the case.

  • Related