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.