Using timeit in Python 2026 with Efficient Code

Efficient Code Mar 15, 2026

Using timeit in Python 2026 with Efficient Code

The timeit module is Python’s built-in tool for accurately measuring the execution time of small code snippets. In 2026, with faster interpreters and free-threading, using timeit properly is essential for reliable benchmarking and performance optimization.

This March 15, 2026 guide shows modern best practices for using timeit effectively in your daily development workflow.

TL;DR — Key Takeaways 2026

  • timeit automatically runs your code multiple times and calculates the best time
  • It disables garbage collection during timing for more accurate results
  • Use timeit.timeit() for simple cases and Timer class for advanced control
  • Always compare before vs after when optimizing
  • Combine with time.perf_counter() for larger functions

1. Basic Usage of timeit


import timeit

# Simple one-liner
time_taken = timeit.timeit('sum(range(10000))', number=1000)
print(f"sum(range(10000)) took {time_taken:.6f} seconds")

# With setup code
setup = "from math import sqrt"
stmt = "sqrt(123456789)"

result = timeit.timeit(stmt, setup=setup, number=100000)
print(f"sqrt took {result:.6f} seconds")

2. Modern timeit Patterns in 2026


import timeit
import numpy as np

def slow_version():
    return [x**2 for x in range(10000)]

def fast_version():
    return np.arange(10000)**2

# Compare two approaches fairly
print("List comprehension:", timeit.timeit(slow_version, number=100))
print("NumPy vectorized:  ", timeit.timeit(fast_version, number=100))

# Using Timer class for more control
timer = timeit.Timer(
    stmt="np.sum(arr**2)",
    setup="import numpy as np; arr = np.arange(100000)"
)

print("Best time:", timer.timeit(number=50))

3. Best Practices for Using timeit in 2026

  • Use number= to control how many times the code runs
  • Use repeat= + min() for more reliable results
  • Always include setup code to avoid measuring import time
  • Time realistic workloads, not tiny toy examples
  • Disable garbage collection during timing with gc.disable() for maximum accuracy
  • Compare relative improvement, not absolute times

4. Recommended timeit Pattern (2026)


def benchmark(stmt, setup="", number=1000, repeat=5):
    """Reliable benchmarking helper"""
    timer = timeit.Timer(stmt=stmt, setup=setup)
    times = timer.repeat(repeat=repeat, number=number)
    best = min(times) / number
    print(f"Best time per loop: {best:.8f} seconds")
    return best

# Usage
benchmark(
    stmt="np.sum(arr**2)",
    setup="import numpy as np; arr = np.arange(100000)",
    number=100
)

How timeit Measures

timeit runs a statement many times in a loop and returns the total time in seconds. It uses a high-resolution clock and temporarily disables garbage collection, which makes measurements of small snippets more consistent.

The number argument sets how many executions form one measurement, and timeit.repeat performs several measurements. Divide the best total by number to get the time per execution.

Pass setup code separately so that preparation, such as creating test data, is not included in the measured time. You can also pass a function object instead of a string.

Worked Example: Setup, number and repeat

We measure string joining with and without setup in the timed statement.

import timeit

setup = "words = [str(i) for i in range(1000)]"
stmt_join = "''.join(words)"
stmt_plus = """
s = ''
for w in words:
    s += w
"""

for name, stmt in [("join", stmt_join), ("+=", stmt_plus)]:
    times = timeit.repeat(stmt, setup=setup, number=2_000, repeat=5)
    print(f"{name:5} {min(times) / 2_000 * 1e6:.2f} µs per call")

with_setup_inside = timeit.timeit(setup + "; " + stmt_join, number=2_000)
setup_outside = timeit.timeit(stmt_join, setup=setup, number=2_000)
print(with_setup_inside > setup_outside)

Dividing the best total by number gives microseconds per call. Putting the setup inside the statement adds list creation to every run, so it measures more than intended.

Practical Tips

From the command line, python -m timeit "sum(range(1000))" gives a quick measurement without writing a script, and it chooses the loop count automatically.

Common Mistakes

  • Including data creation in the timed statement.
  • Forgetting to divide by number.
  • Reading only one measurement instead of the best of several.
  • Timing code that relies on variables not available in setup.

Quick Summary

  • timeit runs code many times with a precise clock.
  • Use setup= for preparation.
  • Use repeat and take the minimum.
  • Divide by number for per-call time.

Conclusion — Using timeit in Python 2026

timeit is the most reliable way to measure small pieces of Python code accurately. In 2026, with increasingly complex applications and free-threading, regularly using timeit helps you make data-driven optimization decisions instead of relying on guesswork. Make it part of your development workflow — time before you optimize.

Next steps:

  • Add timeit benchmarks to your critical functions

Related Tutorials

Share:
Last updated: March 2026
Built-in Functions in Python 2026 str() in Python 2026: String Conversion + Modern Formatting & Best Practices memoryview with JAX in Python 2026: Zero-Copy NumPy → JAX Array Interop + Efficient ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + GPU Pinning & ML Examples memoryview with TensorFlow in Python 2026: Zero-Copy NumPy → Tensor Interop + ML Examples memoryview with NumPy & PyTorch in Python 2026: Zero-Copy Views, Efficient Slicing & ML Interop Examples memoryview with NumPy in Python 2026: Zero-Copy Views, Efficient Slicing & Real ML Examples memoryview() in Python 2026: Zero-Copy Magic for Large Binary Data + Real Examples import() in Python 2026: How It Works, Security Risks & Modern Alternatives (importlib) zip() in Python 2026: How to Use It, strict=True Behavior & Real-World Examples vars() in Python 2026: Accessing Object Namespace + Modern Introspection Patterns type() in Python 2026: Dynamic Type Inspection & Object Creation + Modern Patterns tuple() in Python 2026: Immutable Sequences + Modern Patterns & Best Practices super() in Python 2026: Method Resolution & Modern Inheritance Patterns sum() in Python 2026: Summing Iterables + Modern Numeric Patterns & Best Practices staticmethod() in Python 2026: Static Methods, Utility Functions & Modern Best Practices sorted() in Python 2026: Sorting Iterables + Modern Patterns & Best Practices slice() in Python 2026: Creating Slice Objects + Modern Patterns & Best Practices setattr() in Python 2026: Dynamic Attribute Setting + Modern Patterns & Safety set() in Python 2026: Mutable Sets Creation + Modern Patterns & Best Practices