Time a python function

Image

Time a Python Function Without Arguments

The module function timeit.timeit(stmt, setup, timer, number) accepts four arguments:

  • stmt which is the statement you want to measure; it defaults to ‘pass’.
  • setup which is the code that you run before running the stmt; it defaults to ‘pass’.
  • timer which a timeit.Timer object; it usually has a sensible default value so you don’t have to worry about it.
  • number which is the number of executions you’d like to run the stmt.

Where the timeit.timeit() function returns the number of seconds it took to execute the code.

Now suppose you want to measure a function costly_func implemented like this:

 

 
1
2
def costly_func():
   return map(lambda x: x^2, range(10))

 

You can measure its execution time using timeit:

 

 
1
2
3
4
5
6
7
8
9
10
>>> import timeit
>>> def costly_func():
…     return map(lambda x: x^2, range(10))
>>> # Measure it since costly_func is a callable without argument
>>> timeit.timeit(costly_func)
2.547558069229126
>>> # Measure it using raw statements
>>> timeit.timeit(‘map(lambda x: x^2, range(10))’)
2.3258371353149414

 

Notice that we used two ways to measure this function. The first way passed in the Python callable costly_func while the second way passed in the raw Python statements of costly_func. Although the first way’s timing overhead is a little larger than the second way, we usually prefer the first one since it’s more readable and easier to maintain.

Time a Python Function with Arguments

We can use decorators to measure functions with arguments. Suppose our costly_func is defined in the following way:

 
1
2
def costly_func(lst):
    return map(lambda x: x^2, lst)

 

You could measure it using a decorator defined like this:

 
1
2
3
4
def wrapper(func, *args, **kwargs):
    def wrapped():
        return func(*args, **kwargs)
    return wrapped

 

Now you use this decorator to wrap costly_func with arguments into a function without arguments in order to pass it into timeit.timeit.

 

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>>> def wrapper(func, *args, **kwargs):
…     def wrapped():
…         return func(*args, **kwargs)
…     return wrapped
>>> def costly_func(lst):
…     return map(lambda x: x^2, lst)
>>> short_list = range(10)
>>> wrapped = wrapper(costly_func, short_list)
>>> timeit.timeit(wrapped, number=1000)
0.0032510757446289062
>>> long_list = range(1000)
>>> wrapped = wrapper(costly_func, long_list)
>>> timeit.timeit(wrapped, number=1000)
0.14835596084594727

 

Time a Python Function From Another Module

Suppose you have the function costly_func defined in another module mymodule, how could you measure its time since it’s not locally accessible? Well, you could import it into the local namespace or use the setupargument.

 

 
1
2
3
# mymodule.py
def costly_func():
    return map(lambda x: x^2, range(1000))

 

 

 
1
2
3
4
5
6
>>> timeit.timeit(‘costly_func()’, setup=’from mymodule import costly_func’, number=1000)
0.15768003463745117
# OR just import it in the local namespace
>>> from mymodule import costly_func
>>> timeit.timeit(costly_func, number=1000)
0.15358710289001465

 

Summary

In this article, we learned how to measure a Python function’s execution time using timeit.timeit. Usually, we prefer importing and passing the Python function as a callable object into timeit.timeit since it’s more maintainable. In addition, remember that the default number of executions is 1000000 which could increase the total execution time a lot for certain complex functions.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s