66
77Library usage: see the Timer class.
88
9- Command line usage:
10- python timeit.py [-n N] [-r N] [-s S] [-p] [-h] [--] [statement]
11-
12- Options:
13- -n/--number N: how many times to execute 'statement' (default: see below)
14- -r/--repeat N: how many times to repeat the timer (default 5)
15- -s/--setup S: statement to be executed once initially (default 'pass').
16- Execution time of this setup statement is NOT timed.
17- -p/--process: use time.process_time() (default is time.perf_counter())
18- -v/--verbose: print raw timing results; repeat for more digits precision
19- -u/--unit: set the output time unit (nsec, usec, msec, or sec)
20- -h/--help: print this usage message and exit
21- --: separate options from statement, use when statement starts with -
22- statement: statement to be timed (default 'pass')
23-
24- A multi-line statement may be given by specifying each line as a
25- separate argument; indented lines are possible by enclosing an
26- argument in quotes and using leading spaces. Multiple -s options are
27- treated similarly.
28-
29- If -n is not given, a suitable number of loops is calculated by trying
30- increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the
31- total time is at least 0.2 seconds.
32-
33- Note: there is a certain baseline overhead associated with executing a
34- pass statement. It differs between versions. The code here doesn't try
35- to hide it, but you should be aware of it. The baseline overhead can be
36- measured by invoking the program without arguments.
9+ Command line usage: python -m timeit --help
3710
3811Classes:
3912
@@ -240,6 +213,71 @@ def repeat(stmt="pass", setup="pass", timer=default_timer,
240213 return Timer (stmt , setup , timer , globals ).repeat (repeat , number )
241214
242215
216+ def _make_parser ():
217+ import argparse
218+
219+ parser = argparse .ArgumentParser (
220+ description = """\
221+ Tool avoiding a number of common traps for measuring execution times.
222+ See also Tim Peters' introduction to the Algorithms chapter in the
223+ Python Cookbook, published by O'Reilly.""" ,
224+ epilog = """\
225+ A multi-line statement may be given by specifying each line as a
226+ separate argument; indented lines are possible by enclosing an
227+ argument in quotes and using leading spaces. Multiple -s options are
228+ treated similarly.
229+
230+ If -n is not given, a suitable number of loops is calculated by trying
231+ increasing numbers from the sequence 1, 2, 5, 10, 20, 50, ... until the
232+ total time is at least 0.2 seconds.
233+
234+ Note: there is a certain baseline overhead associated with executing a
235+ pass statement. It differs between versions. The code here doesn't try
236+ to hide it, but you should be aware of it. The baseline overhead can be
237+ measured by invoking the program without arguments.""" ,
238+ formatter_class = argparse .RawTextHelpFormatter ,
239+ allow_abbrev = False ,
240+ )
241+ # use a group to avoid rendering a 'positional arguments' section
242+ group = parser .add_argument_group ()
243+ group .add_argument (
244+ "-n" , "--number" , metavar = "N" , default = 0 , type = int ,
245+ help = "how many times to execute 'statement' (default: see below)" ,
246+ )
247+ group .add_argument (
248+ "-r" , "--repeat" , type = int , metavar = "N" , default = default_repeat ,
249+ help = "how many times to repeat the timer (default: 5)" ,
250+ )
251+ group .add_argument (
252+ "-s" , "--setup" , action = "append" , metavar = "S" , default = [],
253+ help = "statement to be executed once initially (default: 'pass').\n "
254+ "Execution time of this setup statement is NOT timed." ,
255+ )
256+ group .add_argument (
257+ "-u" , "--unit" , choices = ["nsec" , "usec" , "msec" , "sec" ], metavar = "U" ,
258+ help = "set the output time unit (nsec, usec, msec, or sec)" ,
259+ )
260+ group .add_argument (
261+ "-p" , "--process" , action = "store_true" ,
262+ help = "use time.process_time() (default: time.perf_counter())" ,
263+ )
264+ group .add_argument (
265+ "-v" , "--verbose" , action = "count" , default = 0 ,
266+ help = "print raw timing results; repeat for more digits precision" ,
267+ )
268+ # add a dummy option to document '--'
269+ group .add_argument (
270+ "--" , dest = "_" , action = "store_const" , const = None ,
271+ help = "separate options from statement; "
272+ "use when statement starts with -" ,
273+ )
274+ group .add_argument (
275+ "statement" , nargs = "*" ,
276+ help = "statement to be timed (default: 'pass')" ,
277+ )
278+ return parser
279+
280+
243281def main (args = None , * , _wrap_timer = None ):
244282 """Main program, used when run as a script.
245283
@@ -257,53 +295,16 @@ def main(args=None, *, _wrap_timer=None):
257295 is not None, it must be a callable that accepts a timer function
258296 and returns another timer function (used for unit testing).
259297 """
260- if args is None :
261- args = sys .argv [1 :]
262- import getopt
263- try :
264- opts , args = getopt .getopt (args , "n:u:s:r:pvh" ,
265- ["number=" , "setup=" , "repeat=" ,
266- "process" , "verbose" , "unit=" , "help" ])
267- except getopt .error as err :
268- print (err )
269- print ("use -h/--help for command line help" )
270- return 2
271-
272- timer = default_timer
273- stmt = "\n " .join (args ) or "pass"
274- number = 0 # auto-determine
275- setup = []
276- repeat = default_repeat
277- verbose = 0
278- time_unit = None
279- units = {"nsec" : 1e-9 , "usec" : 1e-6 , "msec" : 1e-3 , "sec" : 1.0 }
280- precision = 3
281- for o , a in opts :
282- if o in ("-n" , "--number" ):
283- number = int (a )
284- if o in ("-s" , "--setup" ):
285- setup .append (a )
286- if o in ("-u" , "--unit" ):
287- if a in units :
288- time_unit = a
289- else :
290- print ("Unrecognized unit. Please select nsec, usec, msec, or sec." ,
291- file = sys .stderr )
292- return 2
293- if o in ("-r" , "--repeat" ):
294- repeat = int (a )
295- if repeat <= 0 :
296- repeat = 1
297- if o in ("-p" , "--process" ):
298- timer = time .process_time
299- if o in ("-v" , "--verbose" ):
300- if verbose :
301- precision += 1
302- verbose += 1
303- if o in ("-h" , "--help" ):
304- print (__doc__ , end = "" )
305- return 0
306- setup = "\n " .join (setup ) or "pass"
298+ parser = _make_parser ()
299+ args = parser .parse_args (args )
300+
301+ setup = "\n " .join (args .setup ) or "pass"
302+ stmt = "\n " .join (args .statement ) or "pass"
303+ timer = time .process_time if args .process else default_timer
304+ number = args .number # will be deduced if 0
305+ repeat = max (1 , args .repeat )
306+ verbose = bool (args .verbose )
307+ precision = 3 + max (0 , args .verbose - 1 )
307308
308309 # Include the current directory, so that local imports work (sys.path
309310 # contains the directory of this script, rather than the current
@@ -338,14 +339,16 @@ def callback(number, time_taken):
338339 t .print_exc ()
339340 return 1
340341
342+ units = {"nsec" : 1e-9 , "usec" : 1e-6 , "msec" : 1e-3 , "sec" : 1.0 }
343+ scales = [(scale , unit_name ) for unit_name , scale in units .items ()]
344+ scales .sort (reverse = True )
345+
341346 def format_time (dt ):
342- unit = time_unit
347+ unit = args . unit
343348
344349 if unit is not None :
345350 scale = units [unit ]
346351 else :
347- scales = [(scale , unit ) for unit , scale in units .items ()]
348- scales .sort (reverse = True )
349352 for scale , unit in scales :
350353 if dt >= scale :
351354 break
@@ -362,7 +365,6 @@ def format_time(dt):
362365 % (number , 's' if number != 1 else '' ,
363366 repeat , format_time (best )))
364367
365- best = min (timings )
366368 worst = max (timings )
367369 if worst >= best * 4 :
368370 import warnings
@@ -371,7 +373,7 @@ def format_time(dt):
371373 "slower than the best time (%s)."
372374 % (format_time (worst ), format_time (best )),
373375 UserWarning , '' , 0 )
374- return None
376+ return 0
375377
376378
377379if __name__ == "__main__" :
0 commit comments