How to run an IPython magic from a script (or timing a Python script)

The IPython %timeit magic command does its job well for measuring time required to run some Python code. Now, I want to use something analogous in the Python script. I know about the timeit module, however, it has several disadvantages, for example, how to select the number of runs adaptively? i.e., the default code

import timeit
t=timeit.Timer("code(f)", "from __main__ import code,f")
t.timeit() 

runs the code million times. The %timeit IPyhton magic command does it automatically. I suggest that I could use something like the MATLAB code http://www.mathworks.com/matlabcentral/fileexchange/18798

that does all the job automatically (and also tells if the overhead of the function is large).

How can I call %timeit magic from a Python script (or maybe there is a better timing solution) ?


Solution 1:

It depends a bit on which version of IPython you have. If you have 1.x:

from IPython import get_ipython
ipython = get_ipython()

If you have an older version:

import IPython.core.ipapi  
ipython = IPython.core.ipapi.get()

or

import IPython.ipapi  
ipython = IPython.ipapi.get()

Once that's done, run a magic command like this:

ipython.magic("timeit abs(-42)")

Note that the script must be run via ipython.

Solution 2:

Both IPython and the timeit module, when called with python -m timeit, execute the same loop with a growing value of number until the timing result surpasses a certain threshold that guarantees the time measurement is mostly free of operating system interferences.

You can compare the IPython implementation of the %timeit magic with the Python timeit standard module to see that they are doing mostly the same.

So, answering your question, you should probably replicate the same loop until you find the correct value for the number parameter.

Solution 3:

The following works if one runs the Python script interactively in IPython. E.g., test.py:

def f():
    # Algorithm 1
    pass

def g():
    # Algorithm 2
    pass

# which one is faster?
mgc = get_ipython().magic
mgc(u'%timeit f()')
mgc(u'%timeit g()')

Then run it interactively in IPython

%run -i test.py

to spit out the timings. The -i switch is necessary so that the variables are in scope. I have not figured out how to do this without running an IPython instance, i.e., by simply importing timeit from IPython and using it as a function. However, this solution works for my purposes, which is to automate some timing runs.

Solution 4:

One way to run ipython magic function probably is using embed ipython instance.
For example: (most of the codes are borrowed from ipython website)

from IPython.terminal.embed import InteractiveShellEmbed

ipshell = InteractiveShellEmbed()
ipshell.dummy_mode = True
print('\nTrying to call IPython which is now "dummy":')
ipshell.magic("%timeit abs(-42)");
ipshell()
print('Nothing happened...')

This can work by using python interpreter
PS: using dummy_mode will prevent from invoking interactive shell.