Search code examples
pythondecoratorwrapper

Decorator to output average of historical inputs and outputs to function


I have functions that takes an integer as input and also output an integer. I need to write a decorator to wrap them.

The decorator will save a tuple with two numbers: the average of the inputs and the average of the outputs. For every call to that kind of function, the averages will be printed.

I'm not really sure about the way. I tried this, but it just returns the same input and output of the current function call, how can I calculate the average of all the inputs and outputs till now? or else how do I keep the args amount for the next call to decorator?

def dec(func):
    def wrap(*args):
        counter = len(args)
        avg_input = sum(args) / counter
        avg_output = func(*args)
        print("Average of inputs ", avg_input)
        print("Average of outputs ", avg_output)
    return wrap


@dec
def func(num):
    return num * 2


func(2) # now the avg_inputs = 2 and avg_outputs = 4
func(4) # now the avg_inputs = 3 and avg_outputs = 6
func(6) # now the avg_inputs = 4 and avg_outputs = 8

current output is:

Average of inputs  2.0
Average of outputs  4
Average of inputs  4.0
Average of outputs  8
Average of inputs  6.0
Average of outputs  12

And the output I actually need is:

Average of inputs  2.0
Average of outputs  4
Average of inputs  3.0
Average of outputs  6
Average of inputs  4.0
Average of outputs  8

Solution

  • from functools import wraps
    
    def dec(func):
        @wraps(func)
        def wrap(*args):
            wrap.counter += 1
            wrap.sum_inputs += int(*args)
            wrap.sum_outputs += func(*args)
            avg_input = wrap.sum_inputs / wrap.counter
            avg_output = wrap.sum_outputs / wrap.counter
            print("Average of inputs ", avg_input)
            print("Average of outputs ", avg_output)
            return func(*args)
        wrap.counter = 0
        wrap.sum_inputs = 0
        wrap.sum_outputs = 0
        return wrap