Which code unit executes faster in a Python program? We answer this question with timeit
, a module that benchmarks code fragments.
This module provides a standardized way to perform benchmarks. But usually focusing on higher-level concerns and code quality is a better use of your time.
We must import timeit
with the "import timeit
" statement. This is required unless you use the command-line syntax. Here we time 2 string
-creation expressions.
timeit.timeit
method. We increase the iterations by specifying a number argument.repeat()
method to receive better information.import timeit # The instructions being timed. print('y' * 3) print('y' + 'y' + 'y') # Call timeit on the statements and print the time returned. # ... Specify optional number of iterations. print(timeit.timeit("x = 'y' * 3", number=10000000)) print(timeit.timeit("x = 'y' + 'y' + 'y'", number=10000000))yyy yyy 0.2625868763293428 0.26622904456542135
Repeat is the same as timeit
except it benchmarks repeatedly: it calls timeit
internally several times. The default repetition is 3.
string
-multiplying code shown in the previous example. We start to get repeatable data.import timeit # Call repeat. print(timeit.repeat("x = 'y' * 3", number=100000000, repeat=3)) print(timeit.repeat("x = 'y' + 'y' + 'y'", number=100000000, repeat=3))[2.7390200865497176, 2.7475431168207223, 2.7429300279022177] [2.6369100279087014, 2.631240758828813, 2.6300020650299665]
The timeit
module can be invoked directly from the command-line. This avoids creating an entire new program file. Timeit returns usec (microseconds) in the output.
C:\Users\Sam>C:\Python33\python.exe -m timeit "x = \"y\" * 3" 10000000 loops, best of 3: 0.0273 usec per loop
With timeit
, we can use multiple statements—we separate them with a semicolon. This makes it easier to specify longer code fragments.
import timeit # Use semicolon for multiple statements. print(timeit.repeat("a = 2; a *= 2", number=100000000)) print(timeit.repeat("a = 1; a *= 4", number=100000000))[7.334341642836696, 7.333336683198793, 7.332224095625474] [7.235993375046725, 7.247406798908553, 7.256258872415835]
We can benchmark custom methods in timeit
by specifying a setup argument. In this argument, please specify an import statement that indicates the methods you invoke.
a()
method against the b()
method. As expected, the a()
method is faster—it does less.import timeit def a(): return 1 def b(): return sum([-1, 0, 1, 1]) # Test methods. print(a()) print(b()) # Pass setup argument to call methods. print(timeit.repeat("a()", setup="from __main__ import a")) print(timeit.repeat("b()", setup="from __main__ import b"))1 1 [0.11886792269331777, 0.11894442929800975, 0.11940800745355873] [0.5983422704501993, 0.6003713163771788, 0.6014057764431624]
timeit
The syntax for timeit
calls is difficult—it requires semicolons, and Python does not. The syntax for invoking methods is cumbersome.
timeit
impacts the results. This makes it harder to trust the results of timeit
.It usually costs more time running micro-benchmarks that you will get back in increased speed. With timeit
, we have another benchmarking option.