Note
Go to the end to download the full example code.
Basic Usage Example#
This is a basic usage example of the stopuhr package.
Stop the time with a simple context manager and print the duration.
import time
import stopuhr
timer = stopuhr.Chronometer()
with timer("Sleeping"):
time.sleep(0.1)
Sleeping took 0.10s
stopuhr also provides a default instance of the Chronometer class, which is called stopwatch.
from stopuhr import stopwatch
with stopwatch("Sleeping"):
time.sleep(0.1)
Sleeping took 0.10s
Instead of printing, one can pass any callable to the printer argument, e.g. a logger.
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
logger.addHandler(handler)
with stopwatch("Sleeping", printer=logger.info):
time.sleep(0.1)
2025-06-09 15:20:44,897 - __main__ - INFO - Sleeping took 0.10s
By default, the output is rounded to two decimal places. This can be changed with the res argument.
with stopwatch("Sleeping", res=3):
time.sleep(0.16189)
Sleeping took 0.162s
We can change the default behaviour by passing the arguments to the __init__ method of the Chronometer class.
timer = stopuhr.Chronometer(printer=logger.info, res=3)
with timer("Sleeping"):
time.sleep(0.16189)
2025-06-09 15:20:45,222 - __main__ - INFO - Sleeping took 0.162s
Since stopwatch is just a Chronometer instance, we can just overwrite the default behaviour.
stopwatch.res = 3
with stopwatch("Sleeping"):
time.sleep(0.16189)
stopwatch.res = 2 # back to default
Sleeping took 0.162s
The Chronometer class is stateful, meaning that it can be used to measure multiple durations at once. This also supports the printer and res arguments. The log argument of each call can be used to suppress the output.
for i in range(5):
with stopwatch("Sleeping", log=False):
time.sleep(0.2)
# Print a summary with the mean and standard deviation of the durations.
stopwatch.summary()
Sleeping (with seconds=0.1) took 0.10 ± 0.00s (n=2 -> total=0.20s)
Sleeping took 0.17 ± 0.04s (n=9 -> total=1.52s)
This summary used also the previous calls to the stopwatch function to calculate the mean. We can reset it’s state with the reset method, note that this is happening in-place.
stopwatch.reset()
The previous behavior can also be achieved with the start and stop methods. Here, the stop method also supports the printer, log and res arguments.
for i in range(5):
stopwatch.start("Sleeping")
time.sleep(0.2)
stopwatch.stop("Sleeping", log=False)
stopwatch.summary()
Sleeping took 0.20 ± 0.00s (n=5 -> total=1.00s)
The Chronometer can also measure multiple durations at once, thanks to that feature.
stopwatch.reset()
# Single duration
with stopwatch("A (single 0.2s sleep)", log=False):
time.sleep(0.2)
for i in range(5):
with stopwatch("B (multiple 0.2s sleeps)", log=False):
time.sleep(0.2)
with stopwatch("C (multiple 0.1s sleeps)", log=False):
time.sleep(0.1)
stopwatch.summary()
A (single 0.2s sleep) took 0.20s
B (multiple 0.2s sleeps) took 0.20 ± 0.00s (n=5 -> total=1.00s)
C (multiple 0.1s sleeps) took 0.10 ± 0.00s (n=5 -> total=0.50s)
Because the Chronometer’s __call__ method is a @contextmanager, it can be used as a decorator. This takes the same arguments as the context manager (res, log and printer).
stopwatch.reset()
@stopwatch("Busy Function")
def busy_function():
time.sleep(0.2)
busy_function()
Busy Function took 0.20s
Of course, this can be used to measure multiple functions at once.
stopwatch.reset()
@stopwatch("Busy Function", log=False)
def busy_function():
time.sleep(0.1)
for i in range(5):
busy_function()
stopwatch.summary()
Busy Function took 0.10 ± 0.00s (n=5 -> total=0.50s)