[Python-ideas] Timer that starts as soon as it is imported

Steven D'Aprano steve at pearwood.info
Wed May 27 14:18:32 CEST 2015


On Wed, May 27, 2015 at 04:21:01AM +1000, Chris Angelico wrote:
> On Wed, May 27, 2015 at 4:05 AM, anatoly techtonik <techtonik at gmail.com> wrote:
> >> -- if it could be reset and restarted at need -- why not start it
> >>    manually in the first place?
> >
> > Current ways of measuring script run-time are not cross-platform or
> > not memorizable. I have to reinvent timer code a couple of times, and
> > that's not convenient for the code that is only relevant while debugging.
> 
> Sounds to me like something that doesn't belong in the stdlib, but
> makes a great utility module for private use.

I disagree. I don't think it makes a good utility. I think it is a 
terrible design, for a number of reasons.

(1) Module top level code runs only the first time you import it, after 
that the module is loaded from cache and the code doesn't run again. So 

import timer  # starts a timer

will only start the time the first time you import it. To make it work 
the second time, you have to do:

del sys.modules['timer']
del timer
import timer

(2) Suppose you find some hack that fixes that problem. Now you have 
another problem: it's too hard to control when the timer starts. You 
only have one choice: immediately after the import. So we *have* to 
write our code like this:

import a, b, c  # do our regular imports
setup = x + y + z  # setup everything in advance
import timer
main()

If you move the import timer where the other imports are, as PEP 8 
suggests, you'll time too much: all the setup code as well.

(3) You can only have one timer at a time. You can't run the timer in 
two different threads. (At least not with the simplistic UI of "import 
starts the timer, timer.stop() stops the timer".

Contrast that to how timeit works: timeit is an ordinary module that 
requires no magic to work. Importing it is not the same as running it. 
You can import it at the top of your code, follow it by setup code, and 
run the timeit.Timer whenever you like. You can have as many, or as few, 
timers as you want. The only downside to timeit is that you normally 
have to provide the timed code as a string.

I have a timer context manager which is designed for timing long-running 
code. You write the code in a "with" block:

with Stopwatch():
    do_this()
    do_that()


The context manager starts the timer when you enter, and stops it when 
you leave. By default it prints the time used, but you can easily 
suppress printing and capture the result instead. I've been using this 
for a few years now, and it works well. The only downside is that it 
works too well, so I'm tempted to use it for micro code snippets, so I 
have it print a warning if the time taken is too small:

py> with Stopwatch():
...     n = len("spam")
...
elapsed time is very small; consider using timeit.Timer for 
micro-timings of small code snippets
time taken: 0.000010 seconds



-- 
Steve


More information about the Python-ideas mailing list