Getting Statistical Information on a Function (more of a python learning procress)

Hello,

I’m relatively new to Python and found myself going down a needless rabbit hole but I figured I would inquire about a more elegant way of doing something and hopefully learn something about python.

I have a lot of code with various functions with keyword arguments that I would like to create a wrapper to generate some statistics on the functions.

def getStatistics(fn, *args, numAverages=10, timeBetweenAvgs=gc.DELAY_50MS):
    data = np.zeros(shape=numAverages)
    for x in range(numAverages):
        data[x] = fn(args)
        time.sleep(timeBetweenAvgs)

    print("Average = " + np.average(data))
    print("Stdev = " + np.std(data))

The “fn”'s in questions almost all take keyword arguments and even if they didn’t I’m not even sure how to translate *args into arguments for the fn.

Hope that makes sense, I’m clearly lost.

Thanks!

Just a quick thought. If the only thing you’ll do with fn and *args really is fn(args) (really not fn(*args)?) then it’s a little more work, but it would support any function call with any call signature and any args, to instead use functools.partial, e.g.:

import functools

def getStatistics(partial, numAverages=10, timeBetweenAvgs=gc.DELAY_50MS):
    data = np.zeros(shape=numAverages)
    for x in range(numAverages):
        data[x] = partial()
        time.sleep(timeBetweenAvgs)

    print("Average = " + np.average(data))
    print("Stdev = " + np.std(data))


getStatistics(functools.partial(fn, *args))

Make sure fn isn’t doing cacheing, or re-using artefacts that affect subsequent calls, that would make this an unfair test, too

I think what you’re doing there, broadly speaking, is great! This is definitely a job for a higher-order function - that is, a function that receives another function as a parameter, and does some work generically that involves calling that function.

Unless you specifically need a numpy array for this, I’d recommend using the statistics module; you can collect the data in a simple list, and then do your analysis on that (mean, stdev, and anything else you want).

The normal way to accept arbitrary arguments is *args, **kwargs which will collect up both a sequence of positional arguments and a mapping of keyword arguments. You can then pass those along with fn(*args, **kwargs). In your case, you’re also taking a couple of specific kwargs of your own, so it would look something like this:

def getStatistics(fn, *args, numAverages=10, timeBetweenAvgs=gc.DELAY_50MS, **kwargs):
    ...
    fn(*args, **kwargs)
    ...

That should do what you need.

By the way, it’s normal in Python code to use snake_case rather than camelCase for names; also, what you’re doing here isn’t taking multiple averages, but the average of multiple samples. So I would write it like this:

def get_statistics(fn, *args, samples=10, sample_delay=0.05, **kwargs):

You’ll need to make sure that the names you choose don’t collide with kwargs used by the individual functions though.

Hope that helps!