В чем разница между while 1 и while True?

Я видел два способа создания бесконечного цикла в Python:

  1. while 1:
        do_something()
    
  2. while True:
        do_something()
    

Есть ли разница между ними? Является ли один более питоническим, чем другой?


person Srinivas Reddy Thatiparthy    schedule 14.02.2010    source источник
comment
может быть, бесконечный цикл не питонический? (см. балфа)   -  person Blauohr    schedule 14.02.2010


Ответы (11)


Принципиально это не имеет значения, такие мелочи на самом деле не влияют на то, является ли что-то «питоновским» или нет.

Однако, если вас интересуют мелочи, есть некоторые отличия.

  1. встроенный логический тип не существовал до Python 2.3 поэтому код, предназначенный для запуска в старых версиях, имеет тенденцию использовать форму while 1:. Например, вы увидите его в стандартной библиотеке.

  2. Встроенные функции True и False — это не зарезервированные слова до Python 3 так можно было бы присвоить, изменив их значение. Это помогает в приведенном выше случае, потому что код может выполнять True = 1 для обратной совместимости, но это означает, что имя True нужно искать в словаре глобальных переменных каждый раз, когда оно используется.

  3. Из-за вышеуказанного ограничения байт-код, в который компилируются две версии, отличается в Python 2, поскольку существует оптимизация для постоянных целых чисел, которую он не может использовать для True. Поскольку при компиляции 1 Python может сказать, что он всегда не равен нулю, он удаляет условный переход и вообще не загружает константу:

    >>> import dis
    >>> def while_1():
    ...     while 1:
    ...         pass
    ...
    >>> def while_true():
    ...     while True:
    ...         pass
    ...
    >>> dis.dis(while_1)
      2           0 SETUP_LOOP               5 (to 8)
    
      3     >>    3 JUMP_ABSOLUTE            3
                  6 POP_TOP
                  7 POP_BLOCK
            >>    8 LOAD_CONST               0 (None)
                 11 RETURN_VALUE
    >>> dis.dis(while_true)
      2           0 SETUP_LOOP              12 (to 15)
            >>    3 LOAD_GLOBAL              0 (True)
                  6 JUMP_IF_FALSE            4 (to 13)
                  9 POP_TOP
    
      3          10 JUMP_ABSOLUTE            3
            >>   13 POP_TOP
                 14 POP_BLOCK
            >>   15 LOAD_CONST               0 (None)
                 18 RETURN_VALUE
    

Итак, while True: немного легче читать, а while 1: немного добрее к старым версиям Python. Поскольку в наши дни вам вряд ли понадобится работать на Python 2.2 или беспокоиться о подсчете байт-кода ваших циклов, первое предпочтительнее.

person gz.    schedule 14.02.2010
comment
Я хотел бы отметить, что, по моему скромному мнению, самый питонический способ сделать что-то — это НЕ беспокоиться о таких деталях. Хотя пост абсолютно интересный и информативный, и я это ценю, я поддерживаю утверждение, что while True: более питонический. По крайней мере, как я интерпретирую странный термин pythonic, ваш пробег может отличаться. - person porgarmingduod; 15.02.2010
comment
Только что попробовал сделать True = False, работает как положено, забавно :) - person Antonio; 11.09.2013
comment
Вы все еще можете переопределить True в 3.x, если очень постараетесь. В версии 3.0 это сделает import builtins; builtins.__dict__['True'] = 0; в 3.3 вам нужно проявить гораздо больше творчества, но это все еще возможно. В худшем случае вы всегда можете ctypes перейти к C API (или эквиваленту для других реализаций). Самое интересное, что компилятор предполагает, что вы не можете этого сделать, поэтому некоторые выражения будут скомпилированы, а другие будут использовать ваше новое значение в зависимости от реализации/версии. И если вы сможете найти всему этому хорошее применение… вы, вероятно, сможете найти и лучшие способы использовать свое время… - person abarnert; 16.09.2013

Самый питонический способ всегда будет самым читаемым. Используйте 1_

person porgarmingduod    schedule 14.02.2010
comment
while 1: сильно отличается от for(;;) :-) - person sharjeel; 14.02.2010
comment
@nomemory: вопрос был о Pythonic, который практически не имеет ничего общего с программистами на C. Если вам нужно что-то читаемое для программистов на C, используйте C. - person S.Lott; 15.02.2010
comment
@S.Lott: я пытался сказать, что читабельность - это что-то очень относительное. - person Andrei Ciobanu; 15.02.2010

Это действительно не имеет значения. Ни то, ни другое не сложно прочитать или понять, хотя лично я всегда использовал бы while True, что немного более явно.

В более общем смысле, многие циклы while-break, которые люди пишут на Python, могут быть чем-то другим. Иногда я вижу, как люди пишут i = 0; while True: i += 1 ..., которое можно заменить на for i in itertools.count(), и люди пишут while True: foo = fun() if foo is None: break, когда можно написать for foo in iter(fun, None), что требует обучения, но имеет меньше шаблонов и возможностей для глупых ошибок.

person Mike Graham    schedule 14.02.2010

Ни один.

Оба они означают, что я должен сканировать код в поисках break вместо того, чтобы увидеть условие остановки прямо там, где оно должно быть.

Я стараюсь избегать подобных вещей везде, где это возможно, а если это невозможно, пусть код говорит сам за себя:

while not found_answer:
    check_number += 1
    if check_number == 42:
        found_answer = True

Редактировать: кажется, что слово "избегать" выше было недостаточно ясным. Использование практически бесконечного цикла и выход из него где-то внутри цикла (используя break) обычно следует вообще избегать. Иногда это невозможно. В этом случае мне нравится использовать что-то вроде приведенного выше кода, который, тем не менее, по-прежнему представляет ту же концепцию приведенный выше код является не более чем компромиссом, но, по крайней мере, Я могу показать назначение цикла в начале так же, как не вызывал бы функцию do_something_with_args(*args).

person balpha    schedule 14.02.2010
comment
Но в вашем коде вам просто нужно отсканировать код для found_answer = True. - person Mike Graham; 14.02.2010
comment
Я не понимаю, как это предпочтительнее. Часто причиной использования break является то, что условие остановки не может быть легко или эффективно выражено. Если вы буквально имеете в виду использование такой переменной, как found_answer, тогда вам нужно сканировать ее, а не break, и, как правило, вам все равно понадобится continue вместо break, чтобы выйти из цикла. - person Scott Griffiths; 14.02.2010
comment
@Mike Graham: Да, и я сказал, что вообще хотел бы избежать этого. Если я его использую, я стараюсь сделать все понятным (т. е. удобочитаемым), дав логическому значению имя, которое объясняет, что заставляет этот цикл останавливаться. - person balpha; 14.02.2010
comment
@Scott Griffiths: Но в отличие от True, not found_answer или not received_quit_command что-то сообщает читателю кода. - person balpha; 14.02.2010
comment
@balpha: Это справедливое замечание, но я не могу отделаться от ощущения, что вы вводите новую переменную и добавляете дополнительную условную оценку только для того, чтобы прояснить цель цикла, когда все, что вам действительно нужно, это простой комментарий в конце Начало? - person Scott Griffiths; 14.02.2010
comment
@Scott Griffiths: ... и в операторе (ах) break. Но да, это может быть делом вкуса; Мне нравится использовать имена функций и переменных в качестве комментариев везде, где это возможно; но ваша точка зрения верна. Моя точка зрения по-прежнему заключается в том, что в любом случае попробуйте сделать что-то совершенно другое. Я действительно не понимаю, почему это не ясно из моего ответа. - person balpha; 14.02.2010

ИМО, второй вариант более очевиден.

Если бы вы могли избавиться от while и написать более компактный код, это могло бы быть более питоническим.
Например:

# Get the even numbers in the range 1..10
# Version 1
l = []
n = 1
while 1:
    if n % 2 == 0: l.append(n)
    n += 1
    if n > 10: break
print l

# Version 2
print [i for i in range(1, 11) if i % 2 == 0]

# Version 3
print range(2, 11, 2)
person Nick Dandoulakis    schedule 14.02.2010

Я думаю, что это в основном вопрос стиля. Оба должны быть легко поняты как бесконечный цикл.

Однако лично я предпочитаю второй вариант. Это потому, что для понимания требуется всего один умственный микрошаг, особенно для программистов без опыта работы с C.

person Eli Bendersky    schedule 14.02.2010

Первый будет работать и в тех ранних версиях, где True еще не определен.

person flybywire    schedule 14.02.2010
comment
На данный момент, когда вы программируете для Python 3, поддержание обратной совместимости в любом случае является спорным вопросом. - person Xorlev; 14.02.2010
comment
Интересно, какая была последняя версия Python, в которой True не поддерживался? - person Eli Bendersky; 14.02.2010

Если у вас есть алгоритм, который должен завершаться за конечное время, я бы рекомендовал это, что всегда безопаснее, чем while True:

maxiter = 1000
for i in xrange(maxiter):
   # your code
   # on success:
     break
else:
   # that algorithm has not finished in maxiter steps! do something accordingly
person Olivier Verdier    schedule 14.02.2010
comment
Я не согласен в этом отношении, и существует известная школа, которая делает критерии как можно более точными. Если вы ожидаете, что значение будет равно нулю, скажите так == 0 и не полагайтесь на ‹= 1, поскольку значение -1 может указывать на совершенно неожиданную ветвь предшествующей обработки; бесконечный цикл наверняка кто-то обнаружит, а код, следующий за else, все равно должен это обеспечить. - person guidot; 14.03.2013

Я считаю, что второе выражение является более явным и, следовательно, более pythonic.

person mctylr    schedule 14.02.2010

Это лишь вопрос стиля, любой новичок в программировании поймет любой вариант.

Но второй вариант будет работать только в том случае, если True не был назначен False, что было возможно до Python 3:

>>> True = False
>>> True
False
person AndiDog    schedule 14.02.2010
comment
Это хорошее наблюдение, но любой, кто делает это в проекте с другими разработчиками, почти наверняка будет избит до полусмерти... - person Justin Ethier; 14.02.2010

Лучший способ - "пока правда" с условным выходом из цикла.

person Jesse Kempf    schedule 14.02.2010