File: LP6E/Chapter39/calltracer_desc_class.py
class tracer(object): # A decorator+descriptor
def __init__(self, func): # On @ decorator
self.calls = 0 # Save func for later call
self.func = func
def __call__(self, *args, **kwargs): # On call to original func/meth
self.calls += 1
print(f'call {self.calls} to {self.func.__name__}')
return self.func(*args, **kwargs)
def __get__(self, instance, owner): # On method attribute fetch
return wrapper(self, instance)
class wrapper:
def __init__(self, desc, subj): # Save both instances
self.desc = desc # Route calls back to deco/desc
self.subj = subj
def __call__(self, *args, **kwargs):
return self.desc(self.subj, *args, **kwargs) # Runs tracer.__call__
@tracer
def hack(a, b, c): # hack = tracer(hack)
print(a + b + c) # Uses __call__ only
class Person:
def __init__(self, name, pay):
self.name = name
self.pay = pay
@tracer # giveRaise = tracer(giveRaise)
def giveRaise(self, percent): # Makes giveRaise a descriptor
self.pay *= (1.0 + percent)