A flexible, customizable timer for your Python code.
codetiming
- A flexible, customizable timer for your Python codeInstall codetiming
from PyPI:
$ python -m pip install codetiming
The source code is available on GitHub.
For a complete tutorial on codetiming
, see Python Timer Functions: Three Ways to Monitor Your Code on Real Python.
You can use codetiming.Timer
in several different ways:
As a class:
t = Timer(name="class")
t.start()
# Do something
t.stop()
As a context manager:
with Timer(name="context manager"):
# Do something
As a decorator:
@Timer(name="decorator")
def stuff():
# Do something
Timer
accepts the following arguments when it's created. All arguments are optional:
name
: An optional name for your timertext
: The text that's shown when your timer ends. It should contain a {}
placeholder that will be filled by the elapsed time in seconds (default: "Elapsed time: {:.4f} seconds"
)initial_text
: Show text when your timer starts. You may provide the string to be logged or True
to show the default text "Timer {name} started"
(default: False
)logger
: A function/callable that takes a string argument and will report the elapsed time when the logger is stopped (default: print()
)You can turn off explicit reporting of the elapsed time by setting logger=None
.
In the template text, you can also use explicit attributes to refer to the name
of the timer or log the elapsed time in milliseconds
, seconds
(the default), or minutes
. For example:
t1 = Timer(name="NamedTimer", text="{name}: {minutes:.1f} minutes")
t2 = Timer(text="Elapsed time: {milliseconds:.0f} ms")
Note that the strings used by text
are not f-strings. Instead, they are used as templates that will be populated using .format()
behind the scenes. If you want to combine the text
template with an f-string, you need to use double braces for the template values:
t = Timer(text=f"{__file__}: {{:.4f}}")
text
is also allowed to be a callable like a function or a class. If text
is a callable, it is expected to require one argument: the number of seconds elapsed. It should return a text string that will be logged using logger:
t = Timer(text=lambda secs: f"{secs / 86400:.0f} days")
This allows you to use third-party libraries like humanfriendly
to do the text formatting:
from humanfriendly import format_timespan
t1 = Timer(text=format_timespan)
t2 = Timer(text=lambda secs: f"Elapsed time: {format_timespan(secs)}")
You may include a text that should be logged when the timer starts by setting initial_text
:
t = Timer(initial_text="And so it begins ...")
You can also set initial_text=True
to use a default initial text.
When using Timer
as a class, you can capture the elapsed time when calling .stop()
:
elapsed_time = t.stop()
You can also find the last measured elapsed time in the .last
attribute. The following code will have the same effect as the previous example:
t.stop()
elapsed_time = t.last
Named timers are made available in the class dictionary Timer.timers
. The elapsed time will accumulate if the same name or same timer is used several times. Consider the following example:
>>> import logging
>>> from codetiming import Timer
>>> t = Timer("example", text="Time spent: {:.2f}", logger=logging.warning)
>>> t.start()
>>> t.stop()
WARNING:root:Time spent: 3.58
3.5836678670002584
>>> with t:
... _ = list(range(100_000_000))
...
WARNING:root:Time spent: 1.73
>>> Timer.timers
{'example': 5.312697440000193}
The example shows how you can redirect the timer output to the logging module. Note that the elapsed time spent in the two different uses of t
has been accumulated in Timer.timers
.
You can also get simple statistics about your named timers. Continuing from the example above:
>>> Timer.timers.max("example")
3.5836678670002584
>>> Timer.timers.mean("example")
2.6563487200000964
>>> Timer.timers.stdev("example")
1.311427314335879
timers
support .count()
, .total()
, .min()
, .max()
, .mean()
, .median()
, and .stdev()
.
codetiming
is based on a similar module initially developed for the Midgard Geodesy library at the Norwegian Mapping Authority.