You can avoid this problem entirely if you pass timeit
a function instead of a string. In that case, the function executes in its normal globals and closure environment. So:
timeit.timeit(lambda: function(x))
Or, if you prefer:
timeit.timeit(partial(function, x))
(See here for details. Note that it requires Python 2.6+, so if you need 2.3-2.5, you can't use this trick.)
As the documentation says, "Note that the timing overhead is a little larger in this case because of the extra function calls."
This means that it makes timeit
itself run slower. For example:
>>> def f(): pass
>>> timeit.timeit('timeit.timeit("f()", setup="from __main__ import f")', setup='import timeit', number=1000)
91.66315175301861
>>> timeit.timeit(lambda: timeit.timeit(f), number=100)
94.89793294097762
However, it doesn't affect the actual results:
>>> timeit.timeit(f, number=100000000)
8.81197881908156
>>> timeit.timeit('f()', setup='from __main__ import f', number=100000000)
8.893913001054898
(In the rare cases where it does, that typically means one version or the other wasn't testing the function the way it will be called in your real code, or was testing the wrong closure or similar.)
Note that the actual time taken inside the function here is about 88 seconds, so we've nearly doubled the overhead of timing code… but it's still only added 3% to the total testing time. And the less trivial f
is, the smaller this difference will be.