Python’s with statement, available since Python 2.5, does not seem to be widely used despite being very useful.
Here we describe how to use the with
statement to create a simple timer with the syntax:
>>> with TicToc(): ... some_slow_operations ... Elapsed time is 2.000073 seconds.
Readers familiar with MATLAB will recognize the similarity to the familiar timing mechanism:
> tic ; some_slow_operations; toc Elapsed time is 10.020349 seconds.
Before we describe the TicToc class, let’s review the with
statement. The documentation for reading files suggests that it is a good way to ensure files are properly closed, even if the code reading them raises an exception.
>>> with open('/tmp/workfile', 'r') as f: ... read_data = f.read() >>> f.closed True
The with statement uses two methods, __enter__
, which is run before the block executes, and __exit__
, which is run after the block executes even if an exception is raised. With this in mind, the previous code is mostly equivalent to:
>>> f = open('/tmp/workfile', 'r') >>> f.__enter__() <open file '/tmp/workfile', mode 'r' at 0x10041d810> >>> read_data = f.read() >>> f.__exit__(None, None, None) >>> f.closed True
Here the method file.__exit__
has automatically closed the file.
TicToc
The timer will be implemented as a class defining two methods:
__enter__
which records the start time.__exit__
which prints the difference between the current time and the start time.
import time class TicToc(object): """ A simple code timer. Example ------- >>> with TicToc(): ... time.sleep(2) Elapsed time is 2.000073 seconds. """ def __init__(self, do_print = True): self.do_print = do_print def __enter__(self): self.start_time = time.time() return self def __exit__(self, type, value, traceback): self.elapsed = time.time() - self.start_time if self.do_print: print "Elapsed time is %f seconds." % self.elapsed
>>> from simpletimer import TicToc >>> import time >>> with TicToc(): ... time.sleep(2) ... Elapsed time is 2.000115 seconds. >>> with TicToc(False) as t: ... time.sleep(1) ... >>> t.elapsed 1.0001189708709717
I think a better characterization of a with statement is as a try, finally block. So the open example is actually the same as (I hope WordPress doesn’t kill my indentation)
try:
f = open(‘/tmp/workfile’, ‘r’)
read_data = f.read()
finally:
f.close()
The important thing being that the f.close() is *always* run, even if some unexpected exception is raised. You can even call “return” and it will still be called. It’s the same with __exit__ in a context manager.
And by the way, if you want to use the with statement in Python 2.5, you have to add “from __future__ import with_statement” to the top of the file (or type that out if you’re running interactively).