class tracer(object):                         # Dla metod, ale nie dla funkcji!
    def __init__(self, meth):                 # W momencie dekoracji @
        self.calls = 0                         
        self.meth  = meth
    def __get__(self, instance, owner):       # W momencie pobrania metody
        def wrapper(*args, **kwargs):         # W momencie wywołania metody - pośrednik z self i instancją
            self.calls += 1
            print(f'wywołanie {self.calls} to {self.meth.__name__}')
            return self.meth(instance, *args, **kwargs)
        return wrapper


@tracer
def hack(a, b, c):                           # hack = tracer(hack)
    print(a + b + c)                         # Wykorzystuje jedynie __call__

class Person:
    def __init__(self, name, pay):
        self.name = name
        self.pay  = pay
    @tracer                                  # giveRaise = tracer(giveRaise)
    def giveRaise(self, percent):            # Sprawia, że giveRaise staje się deskryptorem
        self.pay *= (1.0 + percent)

