Search the courses, subjects, tracks, games and features, or jump straight to a page.
Learn it your way
A short class with Sarah and her students. The other ways are under More.
Sign up free to listen. Transcripts are free to read.
Your program feels slow. How would you find out which part is slow?
Measure how long each part takes?
Right. The simplest way is time.time(): read the clock before the block, read it again after, and subtract.
Is that accurate enough?
For a rough number, yes. For short intervals, prefer time.perf_counter(), a high-resolution clock made for measuring durations.
If you time the same tiny snippet twice with time.time(), will you get the same number?
Probably not. Other programs are running at the same time.
Exactly. timeit runs the snippet many times, 1000 in our example, so random noise evens out, and it returns the total time for all the runs.
So to get the time of one run, I divide by number?
Yes. And timeit accepts either a string of code or a function, as in timeit.timeit(test, number=1000).
Copying start and end lines around every block gets tedious. How could a context manager help?
__enter__ could start the clock and __exit__ could stop it!
That's our Timer class. Any block inside with Timer(): gets timed, and the time is printed when the block ends.
What if the block raises an exception?
__exit__ still runs, so you still get the time. It returns None, so the exception carries on after the timing is printed.
Read a clock before and after a block; the difference is how long the block took.
time.time() is fine for rough timing, while time.perf_counter() is made for precise durations.
Runs a snippet or function many times and returns the total time for all runs.
__enter__ starts the clock and __exit__ stops it, so with Timer(): times any block.
A single run varies with machine load, so repeat measurements before drawing conclusions.
A more flexible Timer that uses perf_counter(), takes a label, and keeps the interval for later through as t:
import time
class Timer:
def __init__(self, label="block"):
self.label = label
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.interval = time.perf_counter() - self.start
print(f"{self.label}: {self.interval:.4f} seconds")
return False # do not hide exceptions
with Timer("sum of squares") as t:
total = sum(i * i for i in range(200000))
print("result:", total)
print("interval kept on the object:", t.interval > 0)The timer still reports when the block fails, and the exception still reaches the caller:
import time
class Timer:
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_value, traceback):
elapsed = time.perf_counter() - self.start
status = "failed" if exc_type else "finished"
print(f"block {status} after {elapsed:.4f} seconds")
return False
try:
with Timer():
numbers = [1, 2, 3]
print(numbers[10])
except IndexError as e:
print("caught:", e)timeit.repeat() runs the whole measurement several times; the smallest result is the least disturbed by other activity on the machine:
import timeit
times = timeit.repeat("sum([i for i in range(1000)])", number=1000, repeat=5)
best = min(times)
print(f"best of 5: {best:.4f} seconds for 1000 runs")
print(f"one run: about {best / 1000 * 1e6:.1f} microseconds")Start the clock, run the block, stop the clock, then take stock.
Think of racing toy cars. You click “start” when the car begins and “stop” when it finishes — just like start = time.time() and end = time.time().
“Start-End = Time Spent”
T.I.M.E. - Take a start time, Invoke the block, Mark the end, Evaluate the difference.
Term
How do you time a block with the `time` module?
Click to flip
Term
What does `timeit.timeit(stmt, number=1000)` return?
Click to flip
Term
Which clock is best for measuring short durations?
Click to flip
Term
In a `Timer` context manager, where does the clock start and stop?
Click to flip
Term
Does `__exit__` run if the timed block raises an exception?
Click to flip
Provides simple functions for tracking time.
Measures execution time with high precision.
A Python construct that manages resources using __enter__ and __exit__.
A high-resolution clock for measuring short durations; only the difference between two readings is meaningful.
The difference between the end time and the start time of a block.
A repeatable measurement used to compare the speed of different pieces of code.
You can time blocks of code using the time module or the more accurate timeit module to identify performance bottlenecks.
This topic explores how to measure execution time of code blocks in Python using modules like time and timeit. The time module is suitable for simple timing tasks, while timeit is better for accurate benchmarking, avoiding factors like background processes or startup overhead.
Timing block execution is essential for understanding how long certain parts of your code take to run. This is especially useful for optimizing performance-critical applications. This lesson starts with the simple tools and then wraps them in a context manager class, so that timing any block becomes a single with statement.
The time module provides a quick and simple way to measure the elapsed time between two points in your code.
Example:
import time
start = time.time()
# Code block to measure
sum([i for i in range(100000)])
end = time.time()
print(f"Execution time: {end - start} seconds")time.time() reads the system clock in seconds, so end - start is the elapsed time. The exact number changes from run to run and from machine to machine. For measuring short intervals, time.perf_counter() is the better clock: it has the highest available resolution and is not affected if the system clock is adjusted.
The timeit module is more accurate as it minimizes the impact of background tasks and system calls by running the code multiple times.
Example:
import timeit
execution_time = timeit.timeit("sum([i for i in range(1000)])", number=1000)
print(f"Total time for 1000 runs: {execution_time} seconds")timeit.timeit() returns the total time for all number runs, so divide by number to get the time of one run. By default it uses time.perf_counter() and switches off garbage collection while it measures.
You can also use timeit with a function:
import timeit
def test():
return sum([i for i in range(1000)])
print(timeit.timeit(test, number=1000))You can build your own context manager to time any block of code using with.
import time
class Timer:
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
self.end = time.time()
self.interval = self.end - self.start
print(f"Time taken: {self.interval} seconds")
with Timer():
sum([i for i in range(100000)])This method is elegant and reusable. __enter__ runs when the with block starts and records the start time; __exit__ runs when the block ends and reports the difference. *args collects the three exception details that Python passes to __exit__. Because __exit__ always runs, even when the block raises an exception, the time is reported either way, and since it returns None the exception is not hidden. Writing with Timer() as t: also lets you read t.interval after the block.
Timing execution is like using a stopwatch for athletes. You hit start before the run and stop after. Just like that, Python lets you mark your start and end to calculate the performance of code.
time.time() or time.perf_counter() around a block: a quick, one-off measurement of real code.timeit: comparing small snippets or functions precisely, over many runs.Timer context manager: reusable timing of any block with one with line.