Search code examples
pythonpython-3.xdecoratorpython-decorators

Count how many times each function gets called


I want to count how many times each function get called. I have a wrapper to do the counting and save it into a global variable

def counter(f):
    global function_calls
    function_calls = 0

    def wrapper(*args, **kwargs):
        global function_calls
        function_calls += 1
        return f(*args, **kwargs)

    return wrapper

and then other two functions to be decorated for counting

@counter
def square(x):
    return x * x


@counter
def addition_by_self(x):
    return x + x

Now when I call the function five time each the global variable function_calls returns 10. Which makes sense.

print(square(x=4))
print(square(x=4))
print(square(x=4))
print(square(x=4))
print(square(x=4))

print(addition_by_self(x=4))
print(addition_by_self(x=4))
print(addition_by_self(x=4))
print(addition_by_self(x=4))
print(addition_by_self(x=4))

print(f"Number of the function got called: {function_calls}")

running the file gives the output.

16
16
16
16
16
8
8
8
8
8
Number of the function got called: 10

Now I need some solutions or ideas on how to make the decorator return how many times each function got called, not an aggregation of all the calls. I might have other functions which I need track the number of times they also got called.

Essentially I want to do something like print(function_calls) # or something proper and get the out like: sqaure got called 5 times and addition_by_self got called 5 times


Solution

  • Instead of a single global int, store per-function counts in a dict.

    def counter(f):
        global function_calls
        function_calls = {}
    
        def wrapper(*args, **kwargs):
            global function_calls
            function_calls[f.__name__] = function_calls.setdefault(f.__name__, 0) + 1
            return f(*args, **kwargs)
    
        return wrapper
    

    f might make a better key than f.__name__ (multiple distinct functions could have the same name), but this works as a simple example.