If you've had some experience with coding, you may know that there are many ways to code the same thing. How can we know which one is the best? One of the solutions is to compare the running time. The faster code pieces are commonly better than the slower ones. That's where the timeit module can help. It measures the execution time of a short code snippet and helps you understand how efficient it is. You can use this module both in the Python interface and in the command line.
Timeit operation
Before we get to the code examples, let's take a look at what timeit does. If you're familiar with the time library, you may wonder, why timeit? Put down the time before and after the execution, and then subtract! Easy money. Why is timeit better?
The running time of your program can be affected by background processes that have nothing to do with your code. Time doesn't take it into account, while timeit does. First of all, it runs your code snippet many times, not just once. The default value is 1 000 000. Though, you can change it. So, if you run the timer once, it keeps repeating your code. In the end, you get the total execution time. You can also repeat the timer if you want. In this case, the code is executed 1 000 000 times, and the module records the execution time. After this, the code is executed 1 000 000 times again, and the new execution time is recorded. It happens over and over again, as many times as you specify in the arguments. The default value for the command-line interface is 5. If you're using the command-line interface, it repeats the measurement 5 times and reports the best time. You can do that in the Python interface as well. It allows you to be sure of your code efficiency. However, you cannot completely avoid the system's impact, so don't be surprised when you run the timer several times only to get slightly different results. One more interesting thing – since timeit runs your snippet many times, it provides the running time for many executions, not just one.
As we have mentioned above, the timeit module can be accessed in two ways: in the command line and from Python. We'll start with the latter one.
Introduction to timeit
timeit is a built-in library, so you don't need to install it. Just import it to your code:
import timeit
Now you're ready to go! First, let's take a look at the syntax:
timeit.timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)
stmtmeans statement. It's your code snippet. Note that it must bestr;setupis the code that you don't want to repeat in the loop (for example, animportstatement); it will be executed once, and the module will then subtract the execution time from the result. It must bestr;timeris the function that measures the time. By default, it'stime.perf_counter(), a function well-suited to measuring short durations;numberis the number of thestmtexecutions you want to have in one loop. The default value is 1 000 000;globalsallows you to specify the namespace to run the code. By default,stmtis executed in thetimeitnamespace.
The return value is a float indicating seconds.
Let's look at an example. For now, we'll keep our code snippet simple and add two numbers. Note that the str of your code must be either a multiline with triple quotes or contain a semicolon that separates the expressions. Both of these would work:
snippet_1 = "a=5;b=7;result=a+b"
snippet_2 = """a = 5
b = 7
result = a+b
"""
How do we measure execution time?
snippet = "a=5;b=7;result=a+b"
timeit.timeit(stmt=snippet) # returns: 0.11186270000007426
That's how timeit works. We have provided only stmt. Writing the stmt word is optional; the method would work with timeit.timeit(snippet) only. We've found out that adding 5 to 7 one million times takes Python approximately 0.11 seconds.
Experimenting with options
Let's see how the result will be changed if we alter the number argument. If we decrease it to 1000 repetitions, we will get better timings:
snippet = "a=5;b=7;result=a+b"
timeit.timeit(stmt=snippet, number=1000) # returns: 0.00011770000037358841
Now, let's try 100 000 repetitions. It will take more:
snippet = "a=5;b=7;result=a+b"
timeit.timeit(stmt=snippet, number=100000) # returns: 0.011584099999708997
How to determine the number of repetitions? You can get along with the default value. Another option is to use autorange that will determine the value on its own. We'll get to that a bit later.
You can also repeat the loop. To do it, use the timeit.repeat() method:
timeit.repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=5, number=1000000, globals=None)
As you can see, this method takes the same arguments as timeit.timeit() plus an additional one – repeat. The default value is 5. The output value is a list of float values. Typically, you'd be interested in the lowest value in the list since the higher ones tend to reflect the background activity in the system. Let's have a look at an example:
snippet = "a=5;b=7;result=a+b"
timeit.repeat(stmt=snippet, repeat=3)
# returns: [0.046634299998913775, 0.04249979999985953, 0.040868300000511226]
The value of repeat is 3, so we got three results. timeit.repeat() calls the timeit.timeit() function several times and shows you the results.
Let's take a moment to discuss setup. In this example, we'll find out how fast math.sqrt works. This function calculates the square root of a number. To use it, we need to import the math module first. That's where the setup argument comes in handy — we don't need to import the module one million times:
timeit.timeit(stmt='math.sqrt(4)', setup='import math') # returns: 0.10849280000002182
What if you have a lot of import statements? Setup would take too long. While there's no big problem in having a huge setup statement, there's a more elegant way to do it. Use the globals argument! globals = globals() will allow your stmt to be executed in the global namespace. To put it simply, the function will take the import statements, variables, and functions declared outside the timeit.timeit(). Let's see how it works with the same example of the square root:
import math
timeit.timeit(stmt='math.sqrt(4)', globals=globals()) # returns: 0.11231449999831966
If you don't pass either a setup or a globals argument, you'll get NameError because there's no math inside the timeit namespace. Sometimes, globals=locals() is preferable. You can read a more detailed explanation of that on the StackOverflow forum.
Building a Timer class
You can also build a class with timeit:
timeit.Timer(stmt='pass', setup='pass', timer=<timer function>, globals=None)
Let's say we want to know the list comprehension execution time. Try to do it with a class:
snippet = '[x for x in range(1, 100)]'
t = timeit.Timer(stmt=snippet)
We've created a class instance, but we haven't measured anything yet. To do it, use either the timeit() or repeat() method that works the same way as before:
snippet = '[x for x in range(1, 100)]'
t = timeit.Timer(stmt=snippet)
t.timeit(number=10000) # returns: 0.05218779999995604
We have used the autorange method. It chooses the number of repetitions in the loop automatically, aiming at total execution time >= 0.2 seconds.
snippet = '[x for x in range(1, 100)]'
t = timeit.Timer(stmt=snippet)
t.autorange() # returns: (100000, 0.27417029999924125)
The return value is tuple, where the first element is the number of repetitions, and the second one is the time measured in seconds.
Once we've covered the main points of how timeit works in the Python interface, let's move on to the command-line interface.
Command-line interface
Using timeit from the command line is somewhat straightforward. The module does a lot of work for you, like determining the number of repetitions inside the loop and repeating it several times. First, let's have a look at the syntax:
python -m timeit [-n N] [-r N] [-u U] [-s S] [-h] [statement ...]
-nis thenumberargument. It specifies how many times the statement will be repeated;-ris therepeatargument that determines how many times to repeat the timer;-umeans unit. It allows you to choose a time unit for the output. You can choose eithernsec(nanoseconds),usec(microseconds),msec(millisecond), orsec(seconds);-sissetup— an initial statement that is executed once;-hmeans help and displays a short usage message.
Do you remember the autorange method from the Python interface? As we have already mentioned, the command-line interface does it for you without special commands! If you don't pass the -n parameter, Python will calculate the value automatically.
Let's say we want to see how fast the split() method works. It creates a list from a str and divides it by whitespaces. How do we measure its execution time using the command line? Note that the statement has to be provided in double quotes:
C:\Users\Asus>python -m timeit "'pineapples and bananas'.split()"
2000000 loops, best of 5: 149 nsec per loop
Python has chosen 2000000 as the value for number and has run the timer 5 times. Now, it reports the best time: 149 nanoseconds.
Conclusion
In this topic, we've learned how to use Python timeit module. Let's quickly go through the main points:
timeitmeasures the execution time for short-code snippets;timeit.timeit()is the basic function you'd use most of the time. This function repeats your code in a loop 1 million times, but you can change that using thenumberargument;- Use
setuporglobalsforimportstatements; - Use
timeit.repeat()if you want to calltimeit.timeit()several times; - You can create a
timeit.Timer()class instance; - You can also use
timeitin the command line.