timeit
import timeit The timeit module is Python’s built‑in solution for measuring execution time of small code snippets with minimal overhead. It disables garbage collection, runs the code many times, and uses the most precise timer available on your platform (time.perf_counter). It can be used both as a command‑line tool and programmatically.
Key Functions
timeit.timeit()
Runs a given statement repeatedly and returns the total time taken (in seconds). By default, it runs the statement 1 million times.
import timeit
code = "sum(range(1000))"
elapsed = timeit.timeit(code, number=10000)
print(f"Total time: {elapsed:.4f} seconds")
# Total time: 0.0342 seconds
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
stmt | str | 'pass' | The code to time, as a string or callable |
setup | str | 'pass' | Code that runs once before the timing loop (e.g., imports) |
timer | callable | time.perf_counter | The timer function to use |
number | int | 1000000 | How many times to repeat stmt |
globals | dict | None | Global namespace in which to execute the code |
Returns: float — total time in seconds for number repetitions.
If you pass a callable as stmt, the callable is invoked inside the timing loop. This avoids the overhead of compiling a string each iteration.
def compute():
return sum(range(1000))
# Passing a callable is slightly faster
elapsed = timeit.timeit(compute, number=10000)
timeit.repeat()
Runs timeit() multiple times and returns a list of the individual timings. Useful for seeing variation across runs.
import timeit
times = timeit.repeat("sum(range(1000))", number=1000, repeat=5)
print(f"Times: {times}")
# Times: [0.0034, 0.0032, 0.0033, 0.0035, 0.0031]
print(f"Best: {min(times):.4f}s")
# Best: 0.0031s
Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
stmt | str | 'pass' | Same as timeit() |
setup | str | 'pass' | Same as timeit() |
timer | callable | time.perf_counter | Same as timeit() |
repeat | int | 5 | How many times to run the timing loop |
number | int | 1000000 | How many repetitions per timing loop |
Returns: list[float] — list of times (in seconds) for each repeat.
timeit.default_timer
The default timer function used by the module. On Python 3.3+ this is time.perf_counter, which provides the highest‑resolution clock available.
import timeit
print(timeit.default_timer is time.perf_counter)
# True
You can substitute a custom timer if needed, but perf_counter is almost always the right choice.
Command‑line Interface
timeit can be invoked directly from the command line, which is convenient for quick benchmarking.
python -m timeit "sum(range(1000))"
# 100000 loops, best of 5: 1.23 usec per loop
The module automatically chooses a suitable number of loops and repeats the measurement multiple times, reporting the best time. You can pass setup code with -s:
python -m timeit -s "import numpy as np" "np.sum(np.arange(1000))"
Common command‑line options:
| Option | Meaning |
|---|---|
-n N | Run each measurement loop N times |
-r R | Repeat the measurement R times |
-s S | Execute setup code S before the timing |
-p | Use time.process_time() instead of perf_counter |
-v | Print raw timing results (verbose) |
Examples
Timing different algorithms
Compare the speed of a list comprehension versus a for loop.
import timeit
listcomp = "[i**2 for i in range(1000)]"
forloop = """
result = []
for i in range(1000):
result.append(i**2)
"""
t1 = timeit.timeit(listcomp, number=1000)
t2 = timeit.timeit(forloop, number=1000)
print(f"List comprehension: {t1:.4f}s")
print(f"For loop: {t2:.4f}s")
# List comprehension: 0.045s
# For loop: 0.062s
Using a setup to import modules
Setup code runs once before the timing loop and is not included in the measured time.
import timeit
setup = "import math; x = 10"
stmt = "math.sqrt(x)"
time = timeit.timeit(stmt, setup=setup, number=1000000)
print(f"sqrt time: {time:.3f}s")
# sqrt time: 0.087s
Timing a function with arguments
Wrap the call in a lambda or use functools.partial.
import timeit
def power(base, exp):
return base ** exp
# Using a lambda
t = timeit.timeit(lambda: power(2, 10), number=100000)
print(f"lambda: {t:.3f}s")
# Using a callable reference
t = timeit.timeit(power, setup="from __main__ import power", number=100000)
print(f"callable: {t:.3f}s")
Common Patterns
Best‑of‑five timing
When reporting results, it’s common to take the minimum of several repeats to reduce noise from system load.
import timeit
times = timeit.repeat("sum(range(1000))", number=1000, repeat=5)
best = min(times)
print(f"Best of 5: {best:.4f}s per {1000} loops")
Timing with a custom namespace
If your code relies on global variables, pass them via the globals parameter.
import timeit
my_list = list(range(1000))
time = timeit.timeit("sum(my_list)", globals={"my_list": my_list}, number=10000)
Comparing two snippets
Use timeit.repeat for both and compare the best times.
import timeit
import statistics
times_a = timeit.repeat("sum(range(1000))", number=1000, repeat=7)
times_b = timeit.repeat("sum([i for i in range(1000)])", number=1000, repeat=7)
print(f"A: min={min(times_a):.4f}, mean={statistics.mean(times_a):.4f}")
print(f"B: min={min(times_b):.4f}, mean={statistics.mean(times_b):.4f}")
Errors
IndentationErrors
If your multiline statement is not properly indented, you’ll get an IndentationError. Use explicit newlines (\\n) or triple‑quoted strings.
# Wrong
timeit.timeit("""
for i in range(10):
print(i) # missing indent
""")
# Right
timeit.timeit("""
for i in range(10):
print(i)
""")
NameErrors
If your statement references names that aren’t defined, you’ll get a NameError. Include the necessary definitions in the setup parameter or pass them via globals.
# Wrong
timeit.timeit("my_func()") # my_func not defined
# Right
timeit.timeit("my_func()", setup="def my_func(): return 42")
OverflowError
If number is set too high (e.g., > 10⁹), the loop may cause an OverflowError. Use a smaller number and repeat the measurement instead.