pretty-timeit

timeit, but with the interface it should have had.


Keywords
Timer, timeit, python
License
BSD-3-Clause
Install
pip install pretty-timeit==0.1.0

Documentation

ptimeit

codecov

timeit, but with the interface it should have had.

Why did I write this?

timeit is a great module, but whenever I wanted to use it, I had to look up the syntax, and even after that it was tricky to get things working. I wanted something that had the similar functionality of timeit but an easier, more intuitive syntax.
Under the hood, I take the same approach as timeit does-

  • Everything is imported once.
  • The garbage collector is disabled when the function is run.
  • By default the function runs 1 milllion times.

Installation

With pip.

$ pip install pretty-timeit

With poetry.

$ poetry add pretty-timeit

Usage.

A simple example.

from ptimeit import timethis, Timer

# although this is a decorator, your original function will not be modified.
@timethis() 
def function_to_be_timed():
    lst = [i for i in range(10)]

Timer.run() # Call this at the end of the file.

output

name                 | Execution time
function_to_be_timed | 0.5608107

Note: By default Timer.run() Prints the results to the console. If you want it to return a string, do this.

Timer.run(print_results=False) # returns a string

Mixing positional arguments with keyword arguments.

Positional Arguments must be passed inside a list even if there is one argument.
Keyword arguments must be passed inside a dictionary.
Note the order follows the common idiom of function(*args, **kwargs).

@timethis( [10], {"second_count_up_to":10} )
def function_to_be_timed(count_up_to, second_count_up_to=100):
    lst = [i for i in range(count_up_to)]
    lst2 = [i for i in range(second_count_up_to)]

Timer.run()

Adding custom descriptive names to your functions

If you want to see a different name other than the function name in the final report you can pass that to the decorator using name="" argument.

@timethis([10], name="A list comprehension that counts up to 10")
def function_to_be_timed(count_up_to):
    lst = [i for i in range(count_up_to)]
Timer.run()
name                                      | Execution time
A list comprehension that counts up to 10 | 0.5393135

Changing the number of times the function is repeated.

By default, like timeit, The function is repeated 1 million times, but this can be changed by passing a repeat= to Timer.run() like this.

Timer.run(repeat=100) #The function to be timed will loop for hundred times.

Comparing multiple functions.

A common use case that I have found for the timeit module, is to compare the runtime speed of two different algorithms, this is very easy to do in p-timeit.

@timethis(100, name="using a for loop")
def my_func(count_up_to):
    lst=[]
    for i in range( count_up_to): 
        lst.append(i)

@timethis(100, name="using a List comprehension")
def my_func_2(count_up_to):
    lst = [i for i in range(count_up_to)]

Timer.run(compare=True)

Output

rank | name                       | Execution time
1    | using a List comprehension | 2.3460704000000003
2    | using a for loop           | 4.37266

As you can see the list comprehension is faster than using a for loop.

Note: you can compare as many functions as you like. Not just two. The compare=True flag formats the output, And orders the results from The fastest functions to the slowest. You can still run multiple functions with Timer.run().

Here's an example without compare

@timethis([10], name="using a for loop")
def my_func(count_up_to):
    lst=[]
    for i in range( count_up_to): 
        lst.append(i)

@timethis([10], name="using a List comprehension")
def my_func_2(count_up_to):
    lst = [i for i in range(count_up_to)]

@timethis([10], name="using two lists")
def my_func_3(count_up_to):
    lst = [i for i in range(count_up_to)]
    lst2 = [i for i in range(count_up_to)]

Timer.run()

output

name                       | Execution time
using a for loop           | 0.7021932000000001
using a List comprehension | 0.6186622999999999
using two lists            | 1.0627897000000002

Notice that the functions are ordered as they were defined and not by execution time.