9

I am trying to use timeit.timeit() in order to find how much time it takes to execute a specific line of code. The problem is that this line includes variables and I need to import them somehow, so my question is how? In order to be more clear, the code looks something like this:

def func():
    var1 = 'aaa'
    var2 = 'aab'
    t1 = timeit.timeit('var1==var2', 'from __main__ import ___', number = 10**4) #  here I'm missing what to put after the import

If I were trying to execute this code in __main__ I would just import the variable directly with 'from __main__ import var1, var2' Any solution for this kind of issue?

0

4 Answers 4

10

timeit.Timer takes a callable as well as a string to eval

Changed in version 2.6: The stmt and setup parameters can now also take objects that are callable without arguments. This will embed calls to them in a timer function that will then be executed by timeit(). Note that the timing overhead is a little larger in this case because of the extra function calls.

(also see the source, look for elif hasattr(stmt, '__call__'):).

Create a closure over the variables and pass it to timeit:

def func():
    var1 = 'aaa'
    var2 = 'aab'
    t1 = timeit.timeit(lambda: var1 == var2, number = 10**4)

or equivalently:

def func():
    var1 = 'aaa'
    var2 = 'aab'
    def closure():
        return var1 == var2
    t1 = timeit.timeit(closure, number = 10**4)
Sign up to request clarification or add additional context in comments.

Comments

1

The accepted answer didn't work for me inside pdb debugger and a class method. The solution that worked is to add the variables to globals():

globals()['var1'] = var1
globals()['var2'] = var2
timeit.timeit(lambda: var1 == var2, number = 10**4)

1 Comment

I really like this solution.
1

The globals argument takes a dictionary of variable names and values (i.e. a namespace). Simply pass global and local variables to the globals argument:

def func():
    var1 = 'aaa'
    var2 = 'aab'
    t1 = timeit.timeit('var1 == var2', number=10**4, 
                       globals={**globals(), **locals()})

This will make available all the variables: global and local (including defined functions). In case there are some name collisions, then local variables will take over.

1 Comment

This would be the simplest method. t1 = timeit.timeit('var1==var2', globals=locals(), number = 10**4) is enough for this example.
0

The accepted answer's solution of using lambda creates large overhead. Comparison with an alternative, using a setup string:

func1 117.3 ms
func2  39.0 ms
func1 116.8 ms
func2  41.6 ms
func1 117.2 ms
func2  35.8 ms

If you're trying to measure such a very fast code snippet, or compare the times of multiple, you'd better not overshadow their execution times with such a function call's large overhead and its variance.

Benchmark code that produced the above results (Try it online!):

import timeit

def func1():
    s1 = 'aaa'
    s2 = 'aab'
    return timeit.timeit(lambda: s1 == s2)

def func2():
    setup = '''
s1 = 'aaa'
s2 = 'aab'
'''
    return timeit.timeit('s1 == s2', setup)

for func in [func1, func2] * 3:
    print(func.__name__,
          '%5.1f ms' % (func() * 1e3))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.