Skip to content

Commit d9bef35

Browse files
committed
Patch #1533909: the timeit module now accepts callables in addition to
strings for the code to time and the setup code. Also added two convenience functions for instantiating a Timer and calling its methods.
1 parent 4168c04 commit d9bef35

File tree

4 files changed

+83
-11
lines changed

4 files changed

+83
-11
lines changed

Doc/lib/libtimeit.tex

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ \section{\module{timeit} ---
3131
\method{timeit()} method. The \method{repeat()} method is a
3232
convenience to call \method{timeit()} multiple times and return a list
3333
of results.
34+
35+
\versionchanged[The \var{stmt} and \var{setup} parameters can now also
36+
take objects that are callable without arguments. This
37+
will embed calls to them in a timer function that will
38+
then be executed by \method{timeit()}. Note that the timing
39+
overhead is a little larger in this case because of the
40+
extra function calls]{2.6}
3441
\end{classdesc}
3542

3643
\begin{methoddesc}{print_exc}{\optional{file=\constant{None}}}
@@ -97,6 +104,24 @@ \section{\module{timeit} ---
97104
\end{methoddesc}
98105

99106

107+
Starting with version 2.6, the module also defines two convenience functions:
108+
109+
\begin{funcdesc}{repeat}{stmt\optional{, setup\optional{, timer\optional{,
110+
repeat\code{=3} \optional{, number\code{=1000000}}}}}}
111+
Create a \class{Timer} instance with the given statement, setup code and timer
112+
function and run its \method{repeat} method with the given repeat count and
113+
\var{number} executions.
114+
\versionadded{2.6}
115+
\end{funcdesc}
116+
117+
\begin{funcdesc}{timeit}{stmt\optional{, setup\optional{, timer\optional{,
118+
number\code{=1000000}}}}}
119+
Create a \class{Timer} instance with the given statement, setup code and timer
120+
function and run its \method{timeit} method with \var{number} executions.
121+
\versionadded{2.6}
122+
\end{funcdesc}
123+
124+
100125
\subsection{Command Line Interface}
101126

102127
When called as a program from the command line, the following form is used:

Lib/timeit.py

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,17 @@ def reindent(src, indent):
9090
"""Helper to reindent a multi-line statement."""
9191
return src.replace("\n", "\n" + " "*indent)
9292

93+
def _template_func(setup, func):
94+
"""Create a timer function. Used if the "statement" is a callable."""
95+
def inner(_it, _timer):
96+
setup()
97+
_t0 = _timer()
98+
for _i in _it:
99+
func()
100+
_t1 = _timer()
101+
return _t1 - _t0
102+
return inner
103+
93104
class Timer:
94105
"""Class for timing execution speed of small code snippets.
95106
@@ -109,14 +120,32 @@ class Timer:
109120
def __init__(self, stmt="pass", setup="pass", timer=default_timer):
110121
"""Constructor. See class doc string."""
111122
self.timer = timer
112-
stmt = reindent(stmt, 8)
113-
setup = reindent(setup, 4)
114-
src = template % {'stmt': stmt, 'setup': setup}
115-
self.src = src # Save for traceback display
116-
code = compile(src, dummy_src_name, "exec")
117123
ns = {}
118-
exec code in globals(), ns
119-
self.inner = ns["inner"]
124+
if isinstance(stmt, basestring):
125+
stmt = reindent(stmt, 8)
126+
if isinstance(setup, basestring):
127+
setup = reindent(setup, 4)
128+
src = template % {'stmt': stmt, 'setup': setup}
129+
elif callable(setup):
130+
src = template % {'stmt': stmt, 'setup': '_setup()'}
131+
ns['_setup'] = setup
132+
else:
133+
raise ValueError("setup is neither a string nor callable")
134+
self.src = src # Save for traceback display
135+
code = compile(src, dummy_src_name, "exec")
136+
exec code in globals(), ns
137+
self.inner = ns["inner"]
138+
elif callable(stmt):
139+
self.src = None
140+
if isinstance(setup, basestring):
141+
_setup = setup
142+
def setup():
143+
exec _setup in globals(), ns
144+
elif not callable(setup):
145+
raise ValueError("setup is neither a string nor callable")
146+
self.inner = _template_func(setup, stmt)
147+
else:
148+
raise ValueError("stmt is neither a string nor callable")
120149

121150
def print_exc(self, file=None):
122151
"""Helper to print a traceback from the timed code.
@@ -136,10 +165,13 @@ def print_exc(self, file=None):
136165
sent; it defaults to sys.stderr.
137166
"""
138167
import linecache, traceback
139-
linecache.cache[dummy_src_name] = (len(self.src),
140-
None,
141-
self.src.split("\n"),
142-
dummy_src_name)
168+
if self.src is not None:
169+
linecache.cache[dummy_src_name] = (len(self.src),
170+
None,
171+
self.src.split("\n"),
172+
dummy_src_name)
173+
# else the source is already stored somewhere else
174+
143175
traceback.print_exc(file=file)
144176

145177
def timeit(self, number=default_number):
@@ -189,6 +221,16 @@ def repeat(self, repeat=default_repeat, number=default_number):
189221
r.append(t)
190222
return r
191223

224+
def timeit(stmt="pass", setup="pass", timer=default_timer,
225+
number=default_number):
226+
"""Convenience function to create Timer object and call timeit method."""
227+
return Timer(stmt, setup, timer).timeit(number)
228+
229+
def repeat(stmt="pass", setup="pass", timer=default_timer,
230+
repeat=default_repeat, number=default_number):
231+
"""Convenience function to create Timer object and call repeat method."""
232+
return Timer(stmt, setup, timer).repeat(repeat, number)
233+
192234
def main(args=None):
193235
"""Main program, used when run as a script.
194236

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ Ben Darnell
156156
Jonathan Dasteel
157157
John DeGood
158158
Vincent Delft
159+
Erik Demaine
159160
Roger Dev
160161
Toby Dickenson
161162
Yves Dionne

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ Core and builtins
168168
Library
169169
-------
170170

171+
- Patch #1533909: the timeit module now accepts callables in addition to
172+
strings for the code to time and the setup code. Also added two
173+
convenience functions for instantiating a Timer and calling its methods.
174+
171175
- Patch #1537850: tempfile.NamedTemporaryFile now has a "delete" parameter
172176
which can be set to False to prevent the default delete-on-close
173177
behavior.

0 commit comments

Comments
 (0)