Hi, I'm Harlin and welcome to my blog. I write about Python, Alfresco and other cheesy comestibles.

Python - Using the timeit Module for Quick Speed Evaluations

The timeit module allows for a developer to time a few lines of Python code. It can be used as either a Command-Line Interface or a callable method in a Python script.

From the command line:

$ python -m timeit "[i for i in range(10000)]"

100 loops, best of 3: 4.19 msec per loop

Multiple lines:

$ python -m timeit "for i in range(10000):" "    j = sum([i, 10])" "    k = sum([j, i])"

10 loops, best of 3: 53.2 msec per loop

I personally prefer to use this in the Python interpreter but if you have a need to, you can also use it in a script to time test a function. For example, we want to test the speed to iterate through a list object that was generated by 300 lines of text from a randomly generated ipsum.txt file.

test1.py:

#!/usr/bin/env python

import timeit

with open('ipsum.txt', 'r') as f:
    lines = f.readlines()

def test_list():
    line_list = [line for line in lines]


if __name__ == '__main__':

    print(
        'Testing list: {} ms'.format(
            timeit.timeit(
                'test_list()', setup='from __main__ import test_list', number=10000
            )
        )
    )

The number parameter is used as a number of iterations this code will be tested. The default is 100000.

You may be wondering about calling test_list() and why you need a setup import here. Keep in mind that timeit.timeit() only knows about the code (which is the first option) being passed to it. Since test_list() wasn't defined in this string, timeit uses setup to import test_list.

There may be an occasion where there are a lot of bits to import and having a multi-line setup is something of a hassle. The globals parameter can be used for a convenience. You could then do something like:

timeit.timeit(
    'test_list()', number=10000, global=globals()
)

On my laptop, the output was:

$ ./test1.py 
Testing list: 0.7917806940095033 ms

This can be handy if we wanted to see how much faster it would be to test tuples and deques from a converted list.

test2.py

#!/usr/bin/env python

from collections import deque
import timeit

with open('ipsum.txt', 'r') as f:
    lines = f.readlines()

def test_list():
    line_list = [line for line in lines] 

def test_tuple():
    line_list = [line for line in tuple(lines)]

def test_deque():
    line_list = [line for line in deque(lines)]


if __name__ == '__main__':

    print(
        'Testing list: {} ms'.format(
            timeit.timeit(
                'test_list()', setup='from __main__ import test_list', number=10000
            )
        )
    )

    print(
        'Testing tuple: {} ms'.format(
            timeit.timeit(
                'test_tuple()', setup='from __main__ import test_tuple', number=10000
            )
        )
    )

    print(
        'Testing deque: {} ms'.format(
            timeit.timeit(
                'test_deque()', setup='from __main__ import test_deque', number=10000
            )
        )
    )

My output for this 3-way test looked like:

$ ./test2.py 
Testing list: 0.8192835880036 ms
Testing tuple: 0.8684175600064918 ms
Testing deque: 0.9807582079956774 ms

The tuple and deque tests will show as slightly longer but keep in mind that we did a type conversion of 300 lines of strings each. In these simple tests, that's not a big deal but the purpose of this was just to show you how to use timeit module.

The timeit module is a very handy tool for Python developers when you need a quick idea of how fast a particular routine of code is being executed.

Any Comments, Always Welcome!