tags:

views:

504

answers:

2

Intrigued by this question about infinite loops in perl: http://stackoverflow.com/questions/885908/while-1-vs-for-is-there-a-speed-difference, I decided to run a similar comparison in python. I expected that the compiler would generate the same byte code for while(True): pass and while(1): pass, but this is actually not the case in python2.7.

The following script:

import dis

def while_one():
    while 1:
        pass

def while_true():
    while True:
        pass

print("while 1")
print("----------------------------")
dis.dis(while_one)

print("while True")
print("----------------------------")
dis.dis(while_true)

produces the following results:

while 1
----------------------------
  4           0 SETUP_LOOP               3 (to 6)

  5     >>    3 JUMP_ABSOLUTE            3
        >>    6 LOAD_CONST               0 (None)
              9 RETURN_VALUE        
while True
----------------------------
  8           0 SETUP_LOOP              12 (to 15)
        >>    3 LOAD_GLOBAL              0 (True)
              6 JUMP_IF_FALSE            4 (to 13)
              9 POP_TOP             

  9          10 JUMP_ABSOLUTE            3
        >>   13 POP_TOP             
             14 POP_BLOCK           
        >>   15 LOAD_CONST               0 (None)
             18 RETURN_VALUE        

Using while True is noticeably more complicated. Why is this?

In other contexts, python acts as though True equals 1:

>>> True == 1
True

>>> True + True
2

Why does while distinguish the two?

I noticed that python3 does evaluate the statements using identical operations:

while 1
----------------------------
  4           0 SETUP_LOOP               3 (to 6) 

  5     >>    3 JUMP_ABSOLUTE            3 
        >>    6 LOAD_CONST               0 (None) 
              9 RETURN_VALUE         
while True
----------------------------
  8           0 SETUP_LOOP               3 (to 6) 

  9     >>    3 JUMP_ABSOLUTE            3 
        >>    6 LOAD_CONST               0 (None) 
              9 RETURN_VALUE         

Is there a change in python3 to the way booleans are evaluated?

+35  A: 

In Python 2.x, True is not a keyword, but just a built-in global constant that is defined to 1 in the bool type. Therefore, the interpreter still has to load the contents of True. In other words, True is reassignable:

Python 2.7 (r27:82508, Jul  3 2010, 21:12:11) 
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4
>>> True
4

In Python 3.x, it truly becomes a keyword and a real constant:

Python 3.1.2 (r312:79147, Jul 19 2010, 21:03:37) 
[GCC 4.2.1 (Apple Inc. build 5664)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> True = 4
  File "<stdin>", line 1
SyntaxError: assignment to keyword

thus the interpreter can replace the while True: loop with an infinite loop.

KennyTM
what is the point from making it a global constant ?
M.H
This is exactly what I was confused about. Thank you.
AndrewF
@M.H: AFAIK, it was an expedient to get the keyword into the language.
S.Lott
See http://docs.python.org/whatsnew/2.3.html#pep-285-a-boolean-type and http://www.python.org/dev/peps/pep-0285/ for some of the history.
Ned Deily
With `True = False`, Python 2 can run an infinite loop in no time ^^
AndiDog
A: 

Your Python compiler may know that while(1) is a common shortcut for "loop infinitely" and is optimizing accordingly. The boolean loop appears to be setting the loop up "right", expecting it to eventually end, which is the main difference.

KeithS
why is checking the same boolean constant 'setting up right, expecting it to end'?. 'shortcut for loop infinitely' … that is what `while(true expression)` does, there's no shortcut, and no built-in `for-ever` loop (mmmh, `for(;;)`)
knittl