True, False, None (was re. Pruss's manifesto)

Ron Adam radam2 at tampabay.rr.com
Tue Nov 11 01:10:13 CET 2003


On Mon, 10 Nov 2003 22:11:53 GMT, Alex Martelli <aleax at aleax.it>
wrote:

>Ron Adam wrote:
>   ...
>> Is it possible to make the argument optional for while?  That may
>
>Yes, it is technically possible -- you'd need to play around with the
>Dreaded Grammar File, but as Python grammar tasks go this one seems
>simple.
>
>> allow for an even faster time?
>
>No, there is no reason why "while 1:", "while True:" once True is
>a keyword, and "while:" were the syntax extended to accept it, could
>or should compile down to code that is at all different.
>
>> while:
>> <instructions>
>> 
>> It would be the equivalent as making the default argument for while
>> equal to 1 or True.  Could it optimize to single cpu instruction when
>> that format is used?  No checks or look ups at all?
>
>"while 1:" is _already_ compiled to a single (bytecode, of course)
>instruction with "no checks or look ups at all".  Easy to check:
>
>>>> x=compile('while 1: foop()', '<str>', 'exec')
>>>> dis.dis(x)
>  1           0 SETUP_LOOP              19 (to 22)
>              3 JUMP_FORWARD             4 (to 10)
>              6 JUMP_IF_FALSE           11 (to 20)
>              9 POP_TOP
>        >>   10 LOAD_NAME                0 (foop)
>             13 CALL_FUNCTION            0
>             16 POP_TOP
>             17 JUMP_ABSOLUTE           10
>        >>   20 POP_TOP
>             21 POP_BLOCK
>        >>   22 LOAD_CONST               1 (None)
>             25 RETURN_VALUE
>
>the four bytecodes from 10 to 17 are the loop: name 'foop'
>is loaded, it's called with no argument, its result is
>discarded, and an unconditional jump back to the first of
>these steps is taken (this loop, of course, will only get
>out when function foop [or the lookup for its name] cause
>an exception).  (The 2 opcodes at 6 and 9 never execute,
>and the opcode at 3 could be eliminated if those two were,
>but that's the typical kind of job for a peephole optimizer,
>an easy but low-returns project).
>
>Note the subtle difference when we use True rather than 1:
>
>>>> x=compile('while True: foop()', '<str>', 'exec')
>>>> dis.dis(x)
>  1           0 SETUP_LOOP              19 (to 22)
>        >>    3 LOAD_NAME                0 (True)
>              6 JUMP_IF_FALSE           11 (to 20)
>              9 POP_TOP
>             10 LOAD_NAME                1 (foop)
>             13 CALL_FUNCTION            0
>             16 POP_TOP
>             17 JUMP_ABSOLUTE            3
>        >>   20 POP_TOP
>             21 POP_BLOCK
>        >>   22 LOAD_CONST               0 (None)
>             25 RETURN_VALUE
>
>_Now_, the loop runs all the way through the bytecodes
>from 3 to 20 included (the opcodes at 0 and 21 surround
>it just like they surrounded the unconditional loop we
>just examined).  Before we can get to the "real job" of
>bytecodes 10 to 17, each time around the loop, we need
>to load the value of name True (implying a lookup), do
>a conditional jump on it, otherwise discard its value.
>
>If True was a keyword, the compiler could recognize it and
>generate just the same code as it does for "while 1:" --
>or as it could do for "while:", were that extension of
>the syntax accepted into the language.
>
>
>As to the chances that a patch, implementing "while:" as
>equivalent to "while 1:", might be accepted, I wouldn't
>be particularly optimistic.  Still, one never knows!
>
>
>Alex


Thanks for the detailed explanation.  I would only suggest 'while:' if
there was a performance advantage.   Since there is none,  the only
plus is it save two keystrokes.  That isn't reason enough to change
something that isn't broken.

Thanks for showing me how to use compile() and dis(). 

>>> x=compile('while 1: pass','<str>','exec')
>>> dis.dis(x)
  1           0 SETUP_LOOP              12 (to 15)
              3 JUMP_FORWARD             4 (to 10)
              6 JUMP_IF_FALSE            4 (to 13)
              9 POP_TOP
        >>   10 JUMP_ABSOLUTE           10
        >>   13 POP_TOP
             14 POP_BLOCK
        >>   15 LOAD_CONST               1 (None)
             18 RETURN_VALUE

Yes,  this is as short as it gets.  :-)

In the case of using 'while 1:'  it seems to me you end up loosing
what you gain because you have to test inside the loop which is more
expensive than testing at the 'while' statement. 

>>> x=compile('a=1\nwhile a:\n a=0','<str>','exec')
>>> dis.dis(x)
  1           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (a)

  2           6 SETUP_LOOP              18 (to 27)
        >>    9 LOAD_NAME                0 (a)
             12 JUMP_IF_FALSE           10 (to 25)
             15 POP_TOP

  3          16 LOAD_CONST               1 (0)
             19 STORE_NAME               0 (a)
             22 JUMP_ABSOLUTE            9
        >>   25 POP_TOP
             26 POP_BLOCK
        >>   27 LOAD_CONST               2 (None)
             30 RETURN_VALUE

 
>>> x=compile('a=1\nwhile 1:\n a=0\n if a==0:\n  break','<str>','exec')
>>> dis.dis(x)
  1           0 LOAD_CONST               0 (1)
              3 STORE_NAME               0 (a)

  2           6 SETUP_LOOP              36 (to 45)
        >>    9 JUMP_FORWARD             4 (to 16)
             12 JUMP_IF_FALSE           28 (to 43)
             15 POP_TOP

  3     >>   16 LOAD_CONST               1 (0)
             19 STORE_NAME               0 (a)

  4          22 LOAD_NAME                0 (a)
             25 LOAD_CONST               1 (0)
             28 COMPARE_OP               2 (==)
             31 JUMP_IF_FALSE            5 (to 39)
             34 POP_TOP

  5          35 BREAK_LOOP
             36 JUMP_ABSOLUTE            9
        >>   39 POP_TOP
             40 JUMP_ABSOLUTE           16
        >>   43 POP_TOP
             44 POP_BLOCK
        >>   45 LOAD_CONST               2 (None)
             48 RETURN_VALUE
>>>
 
This requires twice as many instructions, 12 vs 6.   So it's probably
better to avoid 'while 1:' or 'while True':  if possible.   But it is
nice to know 'while 1:' is 20% faster than 'while True:' in those
situations where you need to use it.  

_Ron Adam






More information about the Python-list mailing list