2

I'm struggling with the timeit function in Python, and, on a deeper level, I find myself very frustrated by the quirks of this function. I'm hoping I can get some help with both issues here.

I have a script (call it my_script.py) with a lot of different function definitions, and then a lot of other stuff being calculated below them all. I want to time only one of these functions in particular - let's call it level_99_function(x). I have a big array stored in my_input. My first attempt:

timeit.timeit('f1(x)', setup = 'my_input')

Python returns the error: NameError: global name 'angle' is not defined.

Now my second attempt is to do the following:

print timeit.timeit('level_99_function(x)', setup = 'import numpy as np; import my_script.py; x= np.linspace(0,100)')

This doesn't generate any errors, but the problem is two-fold. First, and most importantly, it still doesn't time the level_99_function (or maybe it just doesn't print to output of the timer for whatever reason?) Second, the import statement seems to be running the entire script on import, which takes forever because of all the stuff I've got in this script aside from my level_99_function.

How do I get the timing of the function in question here? And on a more philosophical level, why is this such a struggle in Python? I've already got a variable and a function defined; all I want to do is time that function call with that variable. It would be nice to not have to write a super long line of code, or write multiple lines of code, or have to import things or any of that stuff. It's as easy as tic and toc in Matlab. I guess the corresponding Python commands would be to use 'time.clock()' before and after the function call, but I've read that this can be inaccurate and misleading.

hobscrk777
  • 2,347
  • 4
  • 23
  • 29
  • 1
    _"the import statement seems to be running the entire script on import"_. Perhaps you need an [`if __name__ == "__main__":`](http://stackoverflow.com/questions/419163/what-does-if-name-main-do) guard around all the non-function code in your module. – Kevin Aug 11 '14 at 15:37
  • `timeit` is not equivalent to `tic...toc`. If you want the functionality of `tic...toc`, do something like: `start = time.clock(); my_function(); print time.clock() - start` – Joel Cornett Aug 11 '14 at 15:37
  • 3
    Re: your frustration: do yourself a favor and instead use iPython with its `%timeit` magic to benchmark your stuff. It is superior to vanilla `timeit` in a lot of ways. For the rest, you will need to provide more code. We can *guess*, but that's not what you came here for. – roippi Aug 11 '14 at 15:38
  • Possible duplicate of [Getting "global name 'foo' is not defined" with Python's timeit](https://stackoverflow.com/questions/551797/getting-global-name-foo-is-not-defined-with-pythons-timeit) – sds Sep 20 '17 at 16:22

2 Answers2

2

You don't need to import numpy everytime within setup, instead you can import the function and variables you want from the current script with from __main__ import ... as shown in the example below.

import timeit
import numpy as np

def func1(x):
    pass

def func2(x):
    pass

def func3(x):
    return np.array(x > 1000)


if __name__ == '__main__':
    x = np.arange(10000)

    time = timeit.timeit('func3(x)', setup='from __main__ import func3, x', number=1000)
    print(time)

The if __name__ == '__main__' block will prevent the code within the if statement from being ran if you import the code from another script, meaning you won't accidentally run your timing tests if you import your functions.

This code only imports func3 and x. I'm only interested in func3 (not func1 and func2) and I've defined a value to test with (I call it x but it's equivalent to your my_input). You don't need to import numpy in this case.

I would however completely and utterly advise you to take roippi's comment into consideration and use IPython. The %timeit magic method is very, very useful.

Community
  • 1
  • 1
Ffisegydd
  • 51,807
  • 15
  • 147
  • 125
0

As an FYI for the future:

I recently submitted a patch against issue2527, which was committed a few days ago to the default branch. So whenever 3.5 is publicly released, you can do this:

timeit.timeit('level_99_function(x)', globals=globals())

Not quite as awesome as iPython's %timeit, I know, but far better than the from __main__ import ... nonsense that you have to do right now. More info in the docs.

roippi
  • 25,533
  • 4
  • 48
  • 73