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

Andrew Barnert abarnert at yahoo.com
Wed May 27 14:29:37 CEST 2015


On May 27, 2015, at 05:18, Steven D'Aprano <steve at pearwood.info> wrote:
> 
>> 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".

Presumably you could add a "timer.restart()" to the UI.

(But in that case, how much does it really cost to use that at the start of the module instead of the magic import anyway? It's like your system uptime; it's hard to find any use for that besides actually reporting system uptime...)

> 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.

For many uses, providing it as a function call works just fine, in which case there are no downsides at all.

> 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

That's a clever idea. I have something very similar, and I sometimes find myself abusing it that way...



More information about the Python-ideas mailing list