cpython: 424eb46f7f3a (original) (raw)
Mercurial > cpython
changeset 102651:424eb46f7f3a
Issue6422 add autorange method to timeit.Timer
Steven D'Aprano steve@pearwood.info | |
---|---|
date | Mon, 15 Aug 2016 01:27:03 +1000 |
parents | e527715bd0b3 |
children | 40b13da7f0f8 |
files | Doc/library/timeit.rst Lib/test/test_timeit.py Lib/timeit.py |
diffstat | 3 files changed, 69 insertions(+), 13 deletions(-)[+] [-] Doc/library/timeit.rst 19 Lib/test/test_timeit.py 22 Lib/timeit.py 41 |
line wrap: on
line diff
--- a/Doc/library/timeit.rst
+++ b/Doc/library/timeit.rst
@@ -100,8 +100,8 @@ The module defines three convenience fun
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
- multiple times and return a list of results.
- method. The :meth:
.repeat
and :meth:.autorange
methods are convenience - methods to call :meth:
.timeit
multiple times. The execution time of setup is excluded from the overall timed execution run.
@@ -134,6 +134,21 @@ The module defines three convenience fun timeit.Timer('for i in range(10): oct(i)', 'gc.enable()').timeit()
Automatically determine how many times to call :meth:`.timeit`.[](#l1.20)
This is a convenience function that calls :meth:`.timeit` repeatedly[](#l1.22)
so that the total time >= 0.2 second, returning the eventual[](#l1.23)
(number of loops, time taken for that number of loops). It calls[](#l1.24)
:meth:`.timeit` with *number* set to successive powers of ten (10,[](#l1.25)
100, 1000, ...) up to a maximum of one billion, until the time taken[](#l1.26)
is at least 0.2 second, or the maximum is reached.[](#l1.27)
If *callback* is given and is not *None*, it will be called after[](#l1.29)
each trial with two arguments: ``callback(number, time_taken)``.[](#l1.30)
+
+
.. method:: Timer.repeat(repeat=3, number=1000000)
Call :meth:.timeit
a few times.
--- a/Lib/test/test_timeit.py +++ b/Lib/test/test_timeit.py @@ -354,6 +354,28 @@ class TestTimeit(unittest.TestCase): s = self.run_main(switches=['-n1', '1/0']) self.assert_exc_string(error_stringio.getvalue(), 'ZeroDivisionError')
- def autorange(self, callback=None):
timer = FakeTimer(seconds_per_increment=0.001)[](#l2.8)
t = timeit.Timer(stmt=self.fake_stmt, setup=self.fake_setup, timer=timer)[](#l2.9)
return t.autorange(callback)[](#l2.10)
- def test_autorange(self):
num_loops, time_taken = self.autorange()[](#l2.13)
self.assertEqual(num_loops, 1000)[](#l2.14)
self.assertEqual(time_taken, 1.0)[](#l2.15)
- def test_autorange_with_callback(self):
def callback(a, b):[](#l2.18)
print("{} {:.3f}".format(a, b))[](#l2.19)
with captured_stdout() as s:[](#l2.20)
num_loops, time_taken = self.autorange(callback)[](#l2.21)
self.assertEqual(num_loops, 1000)[](#l2.22)
self.assertEqual(time_taken, 1.0)[](#l2.23)
expected = ('10 0.010\n'[](#l2.24)
'100 0.100\n'[](#l2.25)
'1000 1.000\n')[](#l2.26)
self.assertEqual(s.getvalue(), expected)[](#l2.27)
+ if name == 'main': unittest.main()
--- a/Lib/timeit.py +++ b/Lib/timeit.py @@ -207,6 +207,26 @@ class Timer: r.append(t) return r
- def autorange(self, callback=None):
"""Return the number of loops so that total time >= 0.2.[](#l3.8)
Calls the timeit method with *number* set to successive powers of[](#l3.10)
ten (10, 100, 1000, ...) up to a maximum of one billion, until[](#l3.11)
the time taken is at least 0.2 second, or the maximum is reached.[](#l3.12)
Returns ``(number, time_taken)``.[](#l3.13)
If *callback* is given and is not None, it will be called after[](#l3.15)
each trial with two arguments: ``callback(number, time_taken)``.[](#l3.16)
"""[](#l3.17)
for i in range(1, 10):[](#l3.18)
number = 10**i[](#l3.19)
time_taken = self.timeit(number)[](#l3.20)
if callback:[](#l3.21)
callback(number, time_taken)[](#l3.22)
if time_taken >= 0.2:[](#l3.23)
break[](#l3.24)
return (number, time_taken)[](#l3.25)
+ def timeit(stmt="pass", setup="pass", timer=default_timer, number=default_number, globals=None): """Convenience function to create Timer object and call timeit method.""" @@ -295,17 +315,16 @@ def main(args=None, *, _wrap_timer=None) t = Timer(stmt, setup, timer) if number == 0: # determine number so that 0.2 <= total time < 2.0
for i in range(1, 10):[](#l3.34)
number = 10**i[](#l3.35)
try:[](#l3.36)
x = t.timeit(number)[](#l3.37)
except:[](#l3.38)
t.print_exc()[](#l3.39)
return 1[](#l3.40)
if verbose:[](#l3.41)
print("%d loops -> %.*g secs" % (number, precision, x))[](#l3.42)
if x >= 0.2:[](#l3.43)
break[](#l3.44)
callback = None[](#l3.45)
if verbose:[](#l3.46)
def callback(number, time_taken):[](#l3.47)
msg = "{num} loops -> {secs:.{prec}g} secs"[](#l3.48)
print(msg.format(num=number, secs=time_taken, prec=precision))[](#l3.49)
try:[](#l3.50)
number, _ = t.autorange(callback)[](#l3.51)
except:[](#l3.52)
t.print_exc()[](#l3.53)
try: r = t.repeat(repeat, number) except:return 1[](#l3.54)