Search code examples
pythondecoratorprofiler

Python get the total execution time of a function


Suppose that I have a function:

def func(x):
    time.sleep(x)
    return x

It will be called in every place when needed, for example, func_a in class A, func_b in class B... And all the modules start from a main function, main().

Now I want to statistic the amount of the called freqs and time of func. It's similar to profiler, but I only want to get the statistics of func; I do not care about other methods.

A Decorator can only get the time once, which is not sufficient for the total time. Another problem is that func overrides a function in another package. It may be called by functions in the package, and it is not easy to add a decorator to every call method.

def time(func):
    def wrapper(*args, **kwargs):
         import time
         st = time.time()
         result = func(*args, **kwargs)
         end = time.time()
         print(f"execution time: {end - st}")
         return result
     return wrapper()
@time
def func(x):
    ...

Is there any simple method that I can use to get the total execution of func with the minimum code?


Solution

  • If you simply want to have the total execution time printed next to the execution time of the current call, you can store the total execution time as a local variable in the decorator and add to it the execution time of each call:

    import time
    
    def timer(func):
        def wrapper(*args, **kwargs):
            nonlocal total
            start = time.time()
            result = func(*args, **kwargs)
            duration = time.time() - start
            total += duration
            print(f"Execution time: {duration}   Total: {total}")
            return result
    
        total = 0
        return wrapper
    

    Demo: Try it online!

    Or if you want to be able to access the total execution time separately, you can expose it as an additional attribute of the wrapper function object:

    import time
    
    def timer(func):
        def wrapper(*args, **kwargs):
            start = time.time()
            result = func(*args, **kwargs)
            duration = time.time() - start
            wrapper.total_time += duration
            print(f"Execution time: {duration}")
            return result
    
        wrapper.total_time = 0
        return wrapper
    

    so that:

    @timer
    def func(x):
        time.sleep(x)
        return x
    
    print(func(1))
    print(func(2))
    print(f'Total: {func.total_time}')
    

    outputs:

    Execution time: 1.00111985206604
    1
    Execution time: 2.0005435943603516
    2
    Total: 3.0016634464263916
    

    Demo: Try it online!