In one of the previous articles (Measure Time in Python – time.time() vs time.clock()), we learned how to use the module timeit
to benchmark a program. Since the program we timed in that article includes only raw statements instead of functions, we’re going to explore how to actually time a function in Python.
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 thestmt
; 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 thestmt
.
Where the timeit.timeit()
function returns the number of seconds it took to execute the code.
- Python Programming – Python User Defined Functions
- Python Programming – Types Of Parameters Or Formal Arguments
- Python’s time.sleep() – Pause, Stop, Wait or Sleep your Python Code
Now suppose you want to measure a function costly_func
implemented like this:
def costly_func(): return map(lambda x: x^2, range(10))
You can measure its execution time using timeit:
>>> 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:
def costly_func(lst): return map(lambda x: x^2, lst)
You could measure it using a decorator defined like this:
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
.
>>> 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 setup
argument.
# mymodule.py def costly_func(): return map(lambda x: x^2, range(1000))
>>> 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 and Tips
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.