From d9bef35e3c0c4c1dfa5760fd76c720afa1956170 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 13 Mar 2007 19:32:21 +0000 Subject: [PATCH] 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. --- Doc/lib/libtimeit.tex | 25 +++++++++++++++++ Lib/timeit.py | 64 +++++++++++++++++++++++++++++++++++-------- Misc/ACKS | 1 + Misc/NEWS | 4 +++ 4 files changed, 83 insertions(+), 11 deletions(-) diff --git a/Doc/lib/libtimeit.tex b/Doc/lib/libtimeit.tex index 1c4e05bafd4..f4f3cc71eb4 100644 --- a/Doc/lib/libtimeit.tex +++ b/Doc/lib/libtimeit.tex @@ -31,6 +31,13 @@ To measure the execution time of the first statement, use the \method{timeit()} method. The \method{repeat()} method is a convenience to call \method{timeit()} multiple times and return a list of results. + +\versionchanged[The \var{stmt} and \var{setup} parameters can now also + take objects that are callable without arguments. This + will embed calls to them in a timer function that will + then be executed by \method{timeit()}. Note that the timing + overhead is a little larger in this case because of the + extra function calls]{2.6} \end{classdesc} \begin{methoddesc}{print_exc}{\optional{file=\constant{None}}} @@ -97,6 +104,24 @@ measured. If so, GC can be re-enabled as the first statement in the \end{methoddesc} +Starting with version 2.6, the module also defines two convenience functions: + +\begin{funcdesc}{repeat}{stmt\optional{, setup\optional{, timer\optional{, + repeat\code{=3} \optional{, number\code{=1000000}}}}}} +Create a \class{Timer} instance with the given statement, setup code and timer +function and run its \method{repeat} method with the given repeat count and +\var{number} executions. +\versionadded{2.6} +\end{funcdesc} + +\begin{funcdesc}{timeit}{stmt\optional{, setup\optional{, timer\optional{, + number\code{=1000000}}}}} +Create a \class{Timer} instance with the given statement, setup code and timer +function and run its \method{timeit} method with \var{number} executions. +\versionadded{2.6} +\end{funcdesc} + + \subsection{Command Line Interface} When called as a program from the command line, the following form is used: diff --git a/Lib/timeit.py b/Lib/timeit.py index 8c0f7a53992..09942f3bb4e 100644 --- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -90,6 +90,17 @@ def reindent(src, indent): """Helper to reindent a multi-line statement.""" return src.replace("\n", "\n" + " "*indent) +def _template_func(setup, func): + """Create a timer function. Used if the "statement" is a callable.""" + def inner(_it, _timer): + setup() + _t0 = _timer() + for _i in _it: + func() + _t1 = _timer() + return _t1 - _t0 + return inner + class Timer: """Class for timing execution speed of small code snippets. @@ -109,14 +120,32 @@ class Timer: def __init__(self, stmt="pass", setup="pass", timer=default_timer): """Constructor. See class doc string.""" self.timer = timer - stmt = reindent(stmt, 8) - setup = reindent(setup, 4) - src = template % {'stmt': stmt, 'setup': setup} - self.src = src # Save for traceback display - code = compile(src, dummy_src_name, "exec") ns = {} - exec code in globals(), ns - self.inner = ns["inner"] + if isinstance(stmt, basestring): + stmt = reindent(stmt, 8) + if isinstance(setup, basestring): + setup = reindent(setup, 4) + src = template % {'stmt': stmt, 'setup': setup} + elif callable(setup): + src = template % {'stmt': stmt, 'setup': '_setup()'} + ns['_setup'] = setup + else: + raise ValueError("setup is neither a string nor callable") + self.src = src # Save for traceback display + code = compile(src, dummy_src_name, "exec") + exec code in globals(), ns + self.inner = ns["inner"] + elif callable(stmt): + self.src = None + if isinstance(setup, basestring): + _setup = setup + def setup(): + exec _setup in globals(), ns + elif not callable(setup): + raise ValueError("setup is neither a string nor callable") + self.inner = _template_func(setup, stmt) + else: + raise ValueError("stmt is neither a string nor callable") def print_exc(self, file=None): """Helper to print a traceback from the timed code. @@ -136,10 +165,13 @@ class Timer: sent; it defaults to sys.stderr. """ import linecache, traceback - linecache.cache[dummy_src_name] = (len(self.src), - None, - self.src.split("\n"), - dummy_src_name) + if self.src is not None: + linecache.cache[dummy_src_name] = (len(self.src), + None, + self.src.split("\n"), + dummy_src_name) + # else the source is already stored somewhere else + traceback.print_exc(file=file) def timeit(self, number=default_number): @@ -189,6 +221,16 @@ class Timer: r.append(t) return r +def timeit(stmt="pass", setup="pass", timer=default_timer, + number=default_number): + """Convenience function to create Timer object and call timeit method.""" + return Timer(stmt, setup, timer).timeit(number) + +def repeat(stmt="pass", setup="pass", timer=default_timer, + repeat=default_repeat, number=default_number): + """Convenience function to create Timer object and call repeat method.""" + return Timer(stmt, setup, timer).repeat(repeat, number) + def main(args=None): """Main program, used when run as a script. diff --git a/Misc/ACKS b/Misc/ACKS index 898af483838..7b6002cd423 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -156,6 +156,7 @@ Ben Darnell Jonathan Dasteel John DeGood Vincent Delft +Erik Demaine Roger Dev Toby Dickenson Yves Dionne diff --git a/Misc/NEWS b/Misc/NEWS index d03c4b540c3..ee4b538a8ab 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -168,6 +168,10 @@ Core and builtins Library ------- +- 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. + - Patch #1537850: tempfile.NamedTemporaryFile now has a "delete" parameter which can be set to False to prevent the default delete-on-close behavior.