Given the following simplified code:
from abc import ABC, abstractmethod
class Parent(ABC):
def __init__(self,*args,**kwargs):
self.parent_name = 'SuperClass'
# global hook to run before each subclass run()
def global_pre_run_hook(self):
pass
@abstractmethod
def run(self, *args, **kwargs):
raise NotImplementedError()
class Child(Parent):
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
self.name = 'ChildClass'
def run(self):
print(f'my parent name is {self.parent_name}')
print(f'my name is {self.name}')
return 22
obj = Child()
result = obj.run()
Is there a way to add functionality so that when the child class run() method is called directly, it first triggers a hook function from the parent class? Assume there is a parent class and a lot of classes that subclass it - would I need to manually add a call global hook() at the beginning of each run() definition for each class that subclasses Parent()? Is there a pythonic way to accomplish this?
The answer by Green Cloak Guy works, but cannot be pickled! To fix this, we need to move the hook creation into __new__. Also, it's a good idea to make use of functools.wraps in the hook creator.
import pickle
from abc import ABC, abstractmethod
from functools import wraps
def create_hook(func, hook):
@wraps(func)
def wrapper(*args, **kwargs):
hook(*args, **kwargs)
return func(*args, **kwargs)
return wrapper
class Parent(ABC):
def __new__(cls, *args, **kwargs):
cls.run = create_hook(cls.run, cls.global_pre_run_hook)
return super().__new__(cls, *args, **kwargs)
# global hook to run before each subclass run()
def global_pre_run_hook(self, *args, **kwargs):
print("Hooked")
@abstractmethod
def run(self, *args, **kwargs):
raise NotImplementedError()
class Child(Parent):
def run(self):
print(f"my parents are {self.__class__.__mro__}")
print(f"my name is {self.__class__.__name__}")
return 22
obj = Child()
result = obj.run()
pickle.dumps(obj)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With