File: LP6E/Chapter39/decorator_state_classes.py
class tracer: # State via instance attributes
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 function
self.calls += 1
print(f'call {self.calls} to {self.func.__name__}')
return self.func(*args, **kwargs)
@tracer
def hack(a, b, c): # Same as: hack = tracer(hack)
print(a + b + c) # Triggers tracer.__init__
@tracer
def code(x, y): # Same as: code = tracer(code)
print(x ** y) # Wraps code in a tracer object
if __name__ == '__main__':
hack(1, 2, 3) # Really calls tracer instance: runs tracer.__call__
hack(a=4, b=5, c=6) # hack is an instance attribute
code(4, 2) # Really calls tracer instance: self.func is code
code(2, y=16) # self.calls is per-decoration here