Question
I want to measure how long a function takes to execute in Python. I tried using timeit, but it did not work as expected:
import timeit
start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)
How can I correctly measure elapsed time in Python, and when should I use timeit versus other timing tools?
Short Answer
By the end of this page, you will understand how to measure elapsed time in Python correctly, why timeit.timeit() is not used like a stopwatch, and when to use time.perf_counter(), time.time(), or timeit for benchmarking code.
Concept
Python has different tools for different kinds of timing.
If you want to measure how much real time passes between two points in your code, use a clock function such as:
time.perf_counter()— best general choice for measuring short durationstime.time()— current wall-clock time, less ideal for precise benchmarking
If you want to benchmark a small piece of code repeatedly to estimate its performance, use timeit.
Your original code does not work because timeit.timeit() is not a timer start/stop function. Instead, it runs a statement many times and returns the total execution time. It is a benchmarking tool, not a stopwatch.
Why this matters
Measuring execution time is useful when you want to:
- compare two implementations
- detect slow parts of a program
- verify performance improvements
- monitor expensive operations like API calls, file processing, or loops
Using the wrong timing tool can give misleading results. For example:
time.time()can be affected by system clock changestimeitadds its own structure for repeated measurement- very short operations need a high-resolution timer like
time.perf_counter()
Mental Model
Think of Python timing tools like different kinds of clocks:
time.perf_counter()is a stopwatch — start it, stop it, and measure elapsed time.time.time()is a wall clock — it tells you the current time.timeitis a lab testing machine — it runs your code many times under controlled conditions to help you benchmark it.
So if you want to know, "How long did this one function call take?" use the stopwatch.
If you want to know, "Which of these two snippets is usually faster?" use the lab testing machine.
Syntax and Examples
The most common way to measure elapsed time in Python is with time.perf_counter().
import time
start = time.perf_counter()
print("hello")
end = time.perf_counter()
print(end - start)
This records the time before and after the code runs, then subtracts the two values.
Measuring a function
import time
def greet():
print("hello")
start = time.perf_counter()
greet()
end = time.perf_counter()
elapsed = end - start
print(f"Elapsed time: {elapsed:.6f} seconds")
Using timeit correctly
timeit is for benchmarking code by running it many times.
import timeit
elapsed = timeit.timeit('print("hello")', number=1)
print(f"Elapsed time: {elapsed:.6f} seconds")
Usually, timeit is more useful for small code snippets that need repeated measurement:
Step by Step Execution
Consider this example:
import time
def slow_task():
total = 0
for i in range(5):
total += i
return total
start = time.perf_counter()
result = slow_task()
end = time.perf_counter()
print(result)
print(f"Elapsed: {end - start:.6f} seconds")
Step by step
-
import time- Loads Python's time-related functions.
-
def slow_task():- Defines a function named
slow_task.
- Defines a function named
-
total = 0- Creates a variable to store a running sum.
-
for i in range(5):- Loops through
0, 1, 2, 3, 4.
- Loops through
-
total += i
Real World Use Cases
Measuring elapsed time is common in real programs.
API requests
import time
import requests
start = time.perf_counter()
response = requests.get("https://example.com")
end = time.perf_counter()
print(f"Request took {end - start:.3f} seconds")
File processing
import time
start = time.perf_counter()
with open("data.txt") as f:
data = f.read()
end = time.perf_counter()
print(f"Read completed in {end - start:.6f} seconds")
Comparing implementations
import timeit
list_time = timeit.timeit(lambda: [x * 2 for x in range(1000)], number=1000)
map_time = timeit.timeit(lambda: list(map(lambda x: x * 2, range(1000))), number=)
(list_time)
(map_time)
Real Codebase Usage
In real projects, developers usually use timing in a few standard ways.
1. Quick profiling around a block of code
import time
start = time.perf_counter()
# code to measure
result = sum(range(100000))
elapsed = time.perf_counter() - start
print(f"Took {elapsed:.6f}s")
This is common during debugging and optimization.
2. Timing inside helper functions
import time
def timed_call(func, *args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
return result, elapsed
This pattern helps reuse timing logic.
3. Logging slow operations
import time
import logging
logging.basicConfig(level=logging.INFO)
start = time.perf_counter()
value = sum(range(500000))
elapsed = time.perf_counter() - start
if elapsed > 0.01:
logging.info("Slow operation: %.6fs", elapsed)
4. Benchmarking implementation choices
Common Mistakes
Here are common beginner mistakes when measuring time in Python.
Mistake 1: Using timeit.timeit() like a stopwatch
Broken code:
import timeit
start = timeit.timeit()
print("hello")
end = timeit.timeit()
print(end - start)
Why it is wrong:
timeit.timeit()runs code and returns how long that benchmark took.- It does not return a "current timestamp" for start and end.
Use this instead:
import time
start = time.perf_counter()
print("hello")
end = time.perf_counter()
print(end - start)
Mistake 2: Timing code that is too small only once
import time
start = time.perf_counter()
sum(range(10))
end = time.perf_counter()
print(end - start)
This may be noisy because the code runs extremely fast.
Better approach:
import timeit
print(timeit.timeit(: (()), number=))
Comparisons
| Tool | Best for | Returns | Good for precise elapsed time? | Notes |
|---|---|---|---|---|
time.perf_counter() | Measuring duration between two points | High-resolution timer value | Yes | Best general choice for elapsed time |
time.time() | Current wall-clock time | Unix timestamp-like value | Sometimes | Less suitable for benchmarking |
timeit.timeit() | Benchmarking code snippets repeatedly | Total execution time | Yes, but for repeated benchmarks | Not a start/stop stopwatch |
cProfile | Profiling full programs | Function-level stats |
Cheat Sheet
import time
start = time.perf_counter()
# code here
end = time.perf_counter()
elapsed = end - start
print(elapsed)
Best choices
- Measure elapsed time:
time.perf_counter() - Get current clock time:
time.time() - Benchmark repeated runs:
timeit.timeit()
timeit examples
import timeit
timeit.timeit('sum(range(100))', number=10000)
import timeit
timeit.timeit(lambda: sum(range(100)), number=10000)
Key rules
- Do not use
timeit.timeit()asstartandendtimestamps. - For short code, prefer repeated timing with
timeit.
FAQ
Should I use timeit or time.perf_counter()?
Use time.perf_counter() when you want to measure elapsed time around a block of code. Use timeit when you want to benchmark a small snippet by running it many times.
Why does timeit.timeit() not work as a start and end timer?
Because it does not return the current time. It executes code repeatedly and returns how long the benchmark took.
Is time.time() good enough for measuring execution time?
Sometimes, yes. But time.perf_counter() is usually the better choice for measuring durations because it has higher resolution and is intended for timing intervals.
How do I measure the runtime of a function in Python?
Wrap the function call with time.perf_counter() before and after, then subtract.
Why do my timing results change between runs?
Execution time can vary because of system load, background tasks, caching, and other environmental factors.
Can I use timeit with a function instead of a string?
Yes. Passing a callable like a function or lambda is often cleaner and safer.
What if I want to profile my whole Python program?
Use a profiler such as cProfile if you need function-level performance details across a larger application.
Mini Project
Description
Build a small Python utility that measures how long different functions take to run. This demonstrates the practical difference between timing a single function call with time.perf_counter() and benchmarking repeated work more systematically.
Goal
Create a reusable timing helper and use it to measure two example functions.
Requirements
- Write a function that accepts another function and measures its elapsed time.
- Create two sample functions to test, such as one using a loop and one using
sum(). - Print both the function result and the elapsed time.
- Use
time.perf_counter()for the timing. - Keep the script runnable as a single Python file.
Keep learning
Related questions
@staticmethod vs @classmethod in Python Explained
Learn the difference between @staticmethod and @classmethod in Python with clear examples, use cases, mistakes, and a mini project.
Call a Function by Name in a Python Module
Learn how to call a function by name in a Python module using strings, getattr, and safe patterns for dynamic function dispatch.
Catch Multiple Exceptions in One except Block in Python
Learn how to catch multiple exceptions in one Python except block using tuples, with examples, mistakes, and real-world usage.