Have you ever wondered why one piece of code takes longer than another, or whether a change actually improved performance? You need to learn how to measure code execution time with timeit. Efficiency in programming is not a luxury but a necessity. Small variations in how you write a loop or process a list can cause dramatic speed differences, especially on large datasets. Python provides a native, extremely precise tool for this job: the timeit module. Unlike simple manual stopwatches, this library is designed to eliminate distortions caused by background processes on the operating system, ensuring reliable results for micro-optimizations.
Why measuring execution time is essential
Many beginner developers rely purely on intuition to decide which function is faster. Intuition often fails when dealing with memory and processor complexity. Understanding your algorithm’s performance lets you identify bottlenecks before they become real production problems. When a system starts to scale, inefficient code can drive server costs up or deliver a poor user experience.
The measurement process also deepens your understanding of data structures. Comparing lookup time in a list versus a dictionary is a valuable practical lesson. The official Python documentation documents timeit as the standard tool for accurate micro-benchmarks.
What is the timeit module?
timeit is a standard library module created specifically to measure the execution time of small code snippets. It runs the code thousands (or millions) of times and computes the average, minimizing the impact of temporary CPU usage fluctuations. If you only use the Python time module with time.time(), you may get imprecise results due to clock resolution or external interruptions.
The major advantage of timeit is that it temporarily disables the garbage collector during measurement. This ensures that memory cleanup time is not unfairly charged against your code’s logic. It is the gold standard for anyone who wants serious, precise benchmarks.
Using timeit from the command line
One of the fastest ways to test an idea is directly in the terminal. You do not need to create a full script to check whether a list comprehension is faster than a traditional for loop:
python -m timeit "[x**2 for x in range(100)]"Python will load the timeit module, execute the code snippet repeatedly, and return the average of the best time obtained across several loops.
Measuring code time inside a script
For in-script use, call timeit.timeit(). It accepts the code to test as a string (or a callable) and the number of repetitions. Let’s compare two ways to concatenate strings — the + operator and the join() method, which is generally recommended for better performance:
import timeit
# Code 1: Using + concatenation
code_plus = 's = ""; lst = ["item"] * 100nfor i in lst: s += i'
# Code 2: Using join
code_join = 'lst = ["item"] * 100; "".join(lst)'
time_plus = timeit.timeit(stmt=code_plus, number=10000)
time_join = timeit.timeit(stmt=code_join, number=10000)
print(f"Time with '+': {time_plus:.5f} seconds")
print(f"Time with join: {time_join:.5f} seconds")The number parameter defines how many times the block runs. If not specified, the default is 1,000,000 iterations.
Using the setup parameter
Often the code you want to measure depends on variables or imports that should not be included in the measured time. The setup argument handles this — code inside setup runs only once before measurement begins:
import timeit
setup_code = "import math"
test_code = "math.sqrt(144)"
result = timeit.timeit(stmt=test_code, setup=setup_code, number=1_000_000)
print(f"Execution time: {result} seconds")Comparing functions directly
Passing strings to timeit can be tedious and error-prone. A cleaner approach is to pass function references directly — especially useful when your functions are already defined in the script:
import timeit
def use_list_comp():
return [str(i) for i in range(1000)]
def use_map():
return list(map(str, range(1000)))
time_list = timeit.timeit(use_list_comp, number=10000)
time_map = timeit.timeit(use_map, number=10000)
print(f"List Comprehension: {time_list}")
print(f"Map Function: {time_map}")Using repeat() for more reliable results
A single measurement can be skewed by a sudden spike in system memory usage. timeit.repeat() runs the full measurement several times and returns a list of results for each round:
import timeit
times = timeit.repeat(stmt="sum(range(100))", repeat=5, number=100_000)
print(f"All times: {times}")
print(f"Best time: {min(times)}")According to Wikipedia on code profiling, the minimum recorded time is generally the most reliable, as it represents the code running with the least possible system interference.
When to avoid timeit
timeit focuses on micro-benchmarks. If you need to analyze a complex system with database access or network API calls, most of the time will be spent waiting on external factors (I/O), making timeit results misleading. For profiling a full script or finding which function inside a large project consumes the most resources, a profiler like cProfile is more appropriate.
Benchmarking tips for accurate results
To get the best results, close other heavy programs while running tests, use enough repetitions so the total time is at least 0.2 seconds, keep tested functions pure (no print calls, which are slow and mask real calculation time), and use repeat() to spot inconsistencies across runs.
Frequently Asked Questions
Does timeit work with functions that take arguments?
Yes. Use a lambda or functools.partial to wrap your function with its arguments before passing it to timeit.
Why do timeit results vary slightly between runs?
Due to current OS load, Python memory management, and other processes running on the machine. That is exactly why using repeat() is recommended.
What is the difference between time.time() and timeit.default_timer()?
default_timer() automatically picks the best available clock for your platform (Windows or Linux), offering higher precision for short intervals.
Does timeit measure memory usage?
No, its exclusive focus is time. For memory measurement use memory_profiler or tracemalloc.
Does timeit disable the garbage collector automatically?
Yes, by default it disables garbage collection to make the CPU time measurement more isolated and consistent.






