I am working through the Python Cookbook.
The following code defines decorators as classes:
import types
from functools import wraps
class Profiled:
def __init__(self, func):
wraps(func)(self)
self.ncalls = 0
def __call__(self, *args, **kwargs):
self.ncalls += 1
return self.__wrapped__(*args, **kwargs)
def __get__(self, instance, cls):
if instance is None:
return self
else:
return types.MethodType(self, instance)
# Example
@Profiled
def add(x, y):
return x + y
class Spam:
@Profiled
def bar(self, x):
print(self, x)
if __name__ == '__main__':
print(add(2,3))
print(add(4,5))
print('ncalls:', add.ncalls)
s = Spam()
s.bar(1)
s.bar(2)
s.bar(3)
print('ncalls:', Spam.bar.ncalls)
yields:
5
9
ncalls: 2
<__main__.Spam object at 0x1187d0828> 1
<__main__.Spam object at 0x1187d0828> 2
<__main__.Spam object at 0x1187d0828> 3
ncalls: 3
It makes sense to me how the Profiled class is decorating these functions, however, I'm struggling to understand what purpose the Profiled __ get __ method serves and why it is needed?
Can anyone explain?