python-3.xtimerpartialtimeitstarmap

How to make timeit.Timer() work with output of itertools.starmap()


I am having a hard time wrapping my head around why i can make timeit.Timer() work with output from functools.partial() but not with output from itertools.starmap().

What I basically need is starmap(func, tuples) to have the same 'attributes' as partial(func, one_arg_only) but be more generally in the sense that I can actually pass into func multiple arguments at the same time.

What's the easiest workaround here ? I tried timeit.Timer(starmap(func,tuples)) and obviously get the notorious error:

ValueError: stmt is neither a string nor callable

I presume this is coz starmap's output is not callable. But how do I work around this ?


Solution

  • The itertools.starmap() function returns an itertools.starmap iterable type whereas functools.partial() returns a functools.partial callable type. timeit.Timer() expects the first argument to be a callable (or a string it can exec()).

    >>> type(itertools.starmap(lambda *args: list(args), [(1, 2)])
    itertools.starmap
    >>> type(functools.partial(lambda x: x+1, 1))
    functools.partial
    

    What you want to do is create a callable that will exhaust the iterable returned by itertools.starmap. One way to do this would be to call the list() function on the output of the starmap:

    # This is the function to call
    >>> example_func = lambda *args: len(args)
    
    # This is the iterable that can call the example_func
    >>> func_callers = itertools.starmap(example_func, [(1, 2)])
    
    # This is the callable that actually processes func_callers
    >>> execute_callers = lambda: list(func_callers)
    
    # And finally using the timer
    >>> timeit.Timer(execute_callers)