Python decorators count function call
The important thing to remember about decorators is that a decorator is a function that takes a function as an argument, and returns yet another function. The returned value - yet another function - is what will be called when the name of the original function is invoked.
This model can be very simple:
def my_decorator(fn):
print("Decorator was called")
return fn
In this case, the returned function is the same as the passed-in function. But that's usually not what you do. Usually, you return either a completely different function, or you return a function that somehow chains or wraps the original function.
In your example, which is a very common model, you have an inner function that is returned:
def helper(x):
helper.calls += 1
return func(x)
This inner function calls the original function (return func(x)
) but it also increments the calls counter.
This inner function is being inserted as a "replacement" for whatever function is being decorated. So when your module foo.succ()
function is looked up, the result is a reference to the inner helper function returned by the decorator. That function increments the call counter and then calls the originally-defined succ
function.
When you decorate a function you "substitute" you're function with the wrapper.
In this example, after the decoration, when you call succ
you are actually calling helper
. So if you are counting calls you have to increase the helper
calls.
You can check that once you decorate a function the name is binded tho the wrapper by checking the attribute __name__ of the decorated function:
def call_counter(func):
def helper(*args, **args):
helper.calls += 1
return func(*args, **args)
helper.calls = 0
return helper
@call_counter
def succ(x):
return x + 1
succ(0)
succ(1)
print(succ.__name__)
>>> 'helper'
print(succ.calls)
>>> 2