Patch by Ben Roberts.
The module defines three convenience functions and a public class:
-.. function:: timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000)
+.. function:: timeit(stmt='pass', setup='pass', timer=<default timer>, number=1000000, globals=None)
Create a :class:`Timer` instance with the given statement, *setup* code and
*timer* function and run its :meth:`.timeit` method with *number* executions.
+ The optional *globals* argument specifies a namespace in which to execute the
+ code.
+
+ .. versionchanged:: 3.5
+ The optional *globals* parameter was added.
.. note::
It will instead return the data specified by your return statement.
-.. function:: repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000)
+.. function:: repeat(stmt='pass', setup='pass', timer=<default timer>, repeat=3, number=1000000, globals=None)
Create a :class:`Timer` instance with the given statement, *setup* code and
*timer* function and run its :meth:`.repeat` method with the given *repeat*
- count and *number* executions.
+ count and *number* executions. The optional *globals* argument specifies a
+ namespace in which to execute the code.
+ .. versionchanged:: 3.5
+ The optional *globals* parameter was added.
.. function:: default_timer()
:func:`time.perf_counter` is now the default timer.
-.. class:: Timer(stmt='pass', setup='pass', timer=<timer function>)
+.. class:: Timer(stmt='pass', setup='pass', timer=<timer function>, globals=None)
Class for timing execution speed of small code snippets.
for setup, and a timer function. Both statements default to ``'pass'``;
the timer function is platform-dependent (see the module doc string).
*stmt* and *setup* may also contain multiple statements separated by ``;``
- or newlines, as long as they don't contain multi-line string literals.
+ or newlines, as long as they don't contain multi-line string literals. The
+ statement will by default be executed within timeit's namespace; this behavior
+ can be controlled by passing a namespace to *globals*.
To measure the execution time of the first statement, use the :meth:`.timeit`
method. The :meth:`.repeat` method is a convenience to call :meth:`.timeit`
will then be executed by :meth:`.timeit`. Note that the timing overhead is a
little larger in this case because of the extra function calls.
+ .. versionchanged:: 3.5
+ The optional *globals* parameter was added.
.. method:: Timer.timeit(number=1000000)
if __name__ == '__main__':
import timeit
print(timeit.timeit("test()", setup="from __main__ import test"))
+
+Another option is to pass :func:`globals` to the *globals* parameter, which will cause the code
+to be executed within your current global namespace. This can be more convenient
+than individually specifying imports::
+
+ def f(x):
+ return x**2
+ def g(x):
+ return x**4
+ def h(x):
+ return x**8
+
+ import timeit
+ print(timeit.timeit('[func(42) for func in (f,g,h)]', globals=globals()))
def fake_callable_stmt(self):
self.fake_timer.inc()
- def timeit(self, stmt, setup, number=None):
+ def timeit(self, stmt, setup, number=None, globals=None):
self.fake_timer = FakeTimer()
- t = timeit.Timer(stmt=stmt, setup=setup, timer=self.fake_timer)
+ t = timeit.Timer(stmt=stmt, setup=setup, timer=self.fake_timer,
+ globals=globals)
kwargs = {}
if number is None:
number = DEFAULT_NUMBER
timer=FakeTimer())
self.assertEqual(delta_time, 0)
+ def test_timeit_globals_args(self):
+ global _global_timer
+ _global_timer = FakeTimer()
+ t = timeit.Timer(stmt='_global_timer.inc()', timer=_global_timer)
+ self.assertRaises(NameError, t.timeit, number=3)
+ timeit.timeit(stmt='_global_timer.inc()', timer=_global_timer,
+ globals=globals(), number=3)
+ local_timer = FakeTimer()
+ timeit.timeit(stmt='local_timer.inc()', timer=local_timer,
+ globals=locals(), number=3)
+
def repeat(self, stmt, setup, repeat=None, number=None):
self.fake_timer = FakeTimer()
t = timeit.Timer(stmt=stmt, setup=setup, timer=self.fake_timer)
default_repeat = 3
default_timer = time.perf_counter
+_globals = globals
+
# Don't change the indentation of the template; the reindent() calls
# in Timer.__init__() depend on setup being indented 4 spaces and stmt
# being indented 8 spaces.
The constructor takes a statement to be timed, an additional
statement used for setup, and a timer function. Both statements
default to 'pass'; the timer function is platform-dependent (see
- module doc string).
+ module doc string). If 'globals' is specified, the code will be
+ executed within that namespace (as opposed to inside timeit's
+ namespace).
To measure the execution time of the first statement, use the
timeit() method. The repeat() method is a convenience to call
multi-line string literals.
"""
- def __init__(self, stmt="pass", setup="pass", timer=default_timer):
+ def __init__(self, stmt="pass", setup="pass", timer=default_timer,
+ globals=None):
"""Constructor. See class doc string."""
self.timer = timer
- ns = {}
+ local_ns = {}
+ global_ns = _globals() if globals is None else globals
if isinstance(stmt, str):
stmt = reindent(stmt, 8)
if isinstance(setup, str):
src = template.format(stmt=stmt, setup=setup)
elif callable(setup):
src = template.format(stmt=stmt, setup='_setup()')
- ns['_setup'] = setup
+ local_ns['_setup'] = setup
else:
raise ValueError("setup is neither a string nor callable")
- self.src = src # Save for traceback display
+ self.src = src # Save for traceback display
code = compile(src, dummy_src_name, "exec")
- exec(code, globals(), ns)
- self.inner = ns["inner"]
+ exec(code, global_ns, local_ns)
+ self.inner = local_ns["inner"]
elif callable(stmt):
self.src = None
if isinstance(setup, str):
_setup = setup
def setup():
- exec(_setup, globals(), ns)
+ exec(_setup, global_ns, local_ns)
elif not callable(setup):
raise ValueError("setup is neither a string nor callable")
self.inner = _template_func(setup, stmt)
return r
def timeit(stmt="pass", setup="pass", timer=default_timer,
- number=default_number):
+ number=default_number, globals=None):
"""Convenience function to create Timer object and call timeit method."""
- return Timer(stmt, setup, timer).timeit(number)
+ return Timer(stmt, setup, timer, globals).timeit(number)
def repeat(stmt="pass", setup="pass", timer=default_timer,
- repeat=default_repeat, number=default_number):
+ repeat=default_repeat, number=default_number, globals=None):
"""Convenience function to create Timer object and call repeat method."""
- return Timer(stmt, setup, timer).repeat(repeat, number)
+ return Timer(stmt, setup, timer, globals).repeat(repeat, number)
def main(args=None, *, _wrap_timer=None):
"""Main program, used when run as a script.
Davide Rizzo
Anthony Roach
Carl Robben
+Ben Roberts
Mark Roberts
Andy Robinson
Jim Robinson
Library
-------
+- Issue #2527: Add a *globals* argument to timeit functions, in order to
+ override the globals namespace in which the timed code is executed.
+ Patch by Ben Roberts.
+
- Issue #22118: Switch urllib.parse to use RFC 3986 semantics for the
resolution of relative URLs, rather than RFCs 1808 and 2396.
Patch by Demian Brecht.