[docs] [issue1397474] timeit execution enviroment

rurpy the second report at bugs.python.org
Tue Jan 11 19:14:06 CET 2011

rurpy the second <rurpy at yahoo.com> added the comment:

I find the changes suggested by T Reedy and refined in the 
patch by E Bendersky an improvement.  However, I found the 
following things confused me when reading it:

"...constructor creates a function..."
the constructor creates a Timeit instance, not a function.  
There is a method on that instance that is the function but 
the way it is phrased in like describing the autos coming off
a Ford production line as "steering wheels".  As written, the 
statement creates an immediate WTF reaction in my mind.

"...that executes the *setup* statement..."
Use of term "statement" here is confusing as that term already
has a well defined meaning in Python docs.  One can't syntactically
use a statement as a function argument.  Only by suspending this
confusion and reading further does one discover that "statement"
here means a string containing text of some python code or a 
callable object.  

Use of "statement" (singular) also directly conflicts with following 
information that states multiple statements are ok.  

Since the synopsis line already refers to "snippets", I think 
continuing to use that is better (having no preexisting conflicting
meanings) than "statement".

"...default to ``'pass'`..." 
The call summary immediately above makes clear what the default
parameter values are.  While fine to repeat it in text, it is not
high priority information so should be moved to later in the

"...or newlines as long as they don’t contain  multi-line string literals..."
What is a multi-line string literal?  The Language Reference -> 
Lexical Analysis -> String Literals section says nothing about 
"multi-line literals".  
Is it "a\nb"?  Or """a
b"""?  Both?
'"a\nb"' actually works.  '"""a
b"""' doesn't of course but it is it is also clearly not valid
python string syntax so I'm not sure that 'multi-line strings need 
even be mentioned.  If it is mentioned then it should be made clear 
that multi-line string literals are not allowed not because timeit
doesn't like them, but because python syntax allows no way to 
embed them in another string.
"...pre-defined user objects..."
What does "pre-defined" mean?  Builtin?  Imported from stdlib?
I would use a more explicit description here.

I also think a short explanation of *why* one needs to import 
program objects in 'setup' makes it a little easier and quicker 
to understand what one is doing with the import, particularly if
one is using timeit somewhere other than __main__..  Thus I 
suggest expanding that section slightly.

Here is my attempt to adjust taking the above observations into 
account.  (Sorry, can't supply a patch since I have slow internet
connection and don't have source.  Text below is just my hand edit
of the "+" lines in Eli's patch.)

  Class for timing execution speed of small code snippets.
  A Timeit instance will contain a function (see :meth:`Timer.timeit`)
  that executes a snippet of "setup" code once and then times some 
  number of executions of "stmt" code .  The code snippets, given as
  arguments *setup* and *stmt* when creating the instance, may be 
  either strings or callable objects.

  If a string, it may contain a python expression, statement, or
  multiple statements separated by ";" or newlines.  Whitespace 
  adhering to the usual Python indentation rules must follow any

  If a callable object, (often a function), the object is called 
  with no arguments.  Note that the timing overhead is a little 
  larger in this case because of the extra function calls required.

  The *setup* and *stmt* parameters default to ``'pass'``.
  The *timer* parameter defaults to a platform-dependent 
  timer function (see the module doc string).

  When the *setup* and *stmt* are run, they are run in a 
  different namespace than that of the code that calls timeit(). 
  To give *stmt* (whether it is a callable name or code string) 
  access to  objects defined in the code that calls timeit, 
  *setup* can import any needed objects.  For example, if your
  code defines function testfunc(), *setup* can contain, 
  ``from __main__ import testfunc``, and code in   *stmt* can
  then call testfunc.

  To measure the execution time of *stmt*, use the :meth:`Timer.timeit()` method. 
  The :meth:`Timer.repeat()` method is a convenience to call :meth:`Timer.timeit()` 
  multiple times and return a list of results.

  Changed in version 2.6: The stmt and setup parameters can now
  also take objects.

Added the line "Whitespace adhering..." because when using backslash-n
in strings it is easy to forget about any needed indentation.  Sentence
could be deleted if deemed too obvious.  There may also be a better 
way to phrase it; currently it might imply that some whitespace
is always neccessary if not enough attention paid to the "usual
indentation rules" phrase.

In msg116330 - Eli Bendersky (eli.bendersky) wrote:

> 1) My tests show that passing the callable instead of the string
> 'test()' actually takes longer to run.

Should the documentation promise that?
I take your word that it also takes longer than running the function's
code directly (outside a function) 
The original "Changed in version 2.6" section said

| Note that the timing overhead is a little larger in this case 
| [callable objects] because of the extra function calls.

Here, "the other case" is presumably the plain code but could 
also be a string function call (e.g. "test()") so I suppose it
is still vacuously true in that case.  Accordingly I reused the
statement above in in my suggested changes.  Perhaps all three 
cases (string code, string function call, callable object) 
should be distinguished further and compared re overhead?

nosy: +rurpy2

Python tracker <report at bugs.python.org>

More information about the docs mailing list