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