I have an abstract base class in Python which defines an abstract method. I want to decorate it with a timer function such that every class extending and implementing this base class is timed and doesn't need to be manually annotated. Here's what I have
import functools
import time
import abc
class Test(metaclass=abc.ABCMeta):
@classmethod
def __subclasshook__(cls, subclass):
return (hasattr(subclass, 'apply') and
callable(subclass.apply))
@abc.abstractmethod
def apply(self, a: str) -> str:
raise NotImplementedError
def timer(func):
@functools.wraps(func)
def wrapper_timer(*args, **kwargs):
start_time = time.perf_counter()
value = func(*args, **kwargs)
end_time = time.perf_counter()
run_time = end_time - start_time
print(f"Finished {func.__name__!r} in {run_time:.4f} secs")
return value
return wrapper_timer
def __getattribute__(self, name):
if name == "apply":
func = getattr(type(self), "apply")
return self.timer(func)
return object.__getattribute__(self, name)
class T2(Test):
def apply(self, a: str) -> str:
return a
if __name__ == '__main__':
t = T2()
t.apply('a')
The error I get is as follow
Traceback (most recent call last):
File "/Users/blah/test.py", line 41, in <module>
t.apply('a')
File "/Users/blah/test.py", line 20, in wrapper_timer
value = func(*args, **kwargs)
TypeError: apply() missing 1 required positional argument: 'a'
I think understand the error python thinks that the apply method of the T2() object is a classmethod however I am not sure why given that I call getattr(type(self), "apply"). Is there a way to get the instance method?