В то время как (1) Vs. пока (правда). Почему разница?

Заинтригованный этим вопросом о бесконечных циклах в perl: while (1) Vs. for (;;) Есть ли разница в скорости?, я решил запустить аналогичное сравнение в python. Я ожидал, что компилятор будет генерировать один и тот же байтовый код для while(True): pass и while(1): pass, но на самом деле это не так в python2.7.

Следующий 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)

дает следующие результаты:

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        

Использование while True заметно сложнее. Почему это?

В других контекстах питон действует так, как будто True равно 1:

>>> True == 1
True

>>> True + True
2

Почему while отличает два?

Я заметил, что python3 оценивает операторы, используя идентичные операции:

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         

Есть ли изменение в python3 на способ вычисления булевых элементов?

Ответ 1

В Python 2.x True не является ключевым словом, а просто встроенная глобальная константа, которая определена как 1 в тип bool. Поэтому интерпретатору по-прежнему приходится загружать содержимое True. Другими словами, True переназначается:

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

В Python 3.x он действительно становится ключевым словом и реальной константой:

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

Таким образом, интерпретатор может заменить цикл while True: на бесконечный цикл.

Ответ 2

Это не совсем правильно,

таким образом, интерпретатор может заменить while while: цикл с бесконечным циклом.

поскольку все еще может выйти из цикла. Но верно, что такое предложение цикла else никогда не будет доступно в Python 3. И также верно, что упрощение поиска значения заставляет его работать так же быстро, как while 1 в Python 2.

Сравнение производительности

Демонстрируя разницу во времени для несколько нетривиального цикла while:

Настройка

def while1():
    x = 0
    while 1:
        x += 1
        if x == 10:
            break

def whileTrue():
    x = 0
    while True:
        x += 1
        if x == 10:
            break

Python 2

>>> import timeit
>>> min(timeit.repeat(while1))
0.49712109565734863
>>> min(timeit.repeat(whileTrue))
0.756627082824707

Python 3

>>> import timeit
>>> min(timeit.repeat(while1))
0.6462970309949014
>>> min(timeit.repeat(whileTrue))
0.6450748789939098

Объяснение

Чтобы объяснить разницу, в Python 2:

>>> import keyword
>>> 'True' in keyword.kwlist
False

но в Python 3:

>>> import keyword
>>> 'True' in keyword.kwlist
True
>>> True = 'true?'
  File "<stdin>", line 1
SyntaxError: can't assign to keyword

Так как True является ключевым словом в Python 3, интерпретатору не нужно искать значение, чтобы увидеть, заменил ли кто-нибудь его другое значение. Но поскольку для другого значения можно присваивать True, интерпретатор должен каждый раз искать его.

Заключение для Python 2

Если у вас жесткий, длинный цикл в Python 2, вы, вероятно, должны использовать while 1: вместо while True:.

Заключение для Python 3

Используйте while True:, если у вас нет условий для выхода из цикла.