Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 13 из 20 Начальный 15 мин 100 XP

Бесконечный цикл while True в Python

Цикл, который сам не кончается, а останавливается по событию: меню, игра-угадайка, поток задач. while True плюс break — главный цикл интерфейсов и игр.

Редакция Питоники

Все циклы до сих пор знали, когда им кончаться: список кончился, счётчик дошёл до границы, условие стало ложным. Но у многих программ конца нет — есть событие: пользователь выбрал выход, игрок угадал число, сервер получил команду останова. Для таких программ цикл пишут наоборот: сначала бесконечный, выход — по событию через break. Разбираем while True — главный цикл интерфейсов и игр.

while True: бесконечный по построению

Запись while True честна до прямолинейности: условие цикла — истина без всяких проверок. Сам он крутиться будет вечно; вечность обрывает только break:

обратный отсчёт на while True
charge = 3
while True:
    print('Заряд:', charge)
    charge -= 1
    if charge == 0:
        print('Выключаюсь')
        break
Вывод
Заряд: 3
Заряд: 2
Заряд: 1
Выключаюсь

Проверка if charge == 0 стоит в теле и срабатывает по ходу итерации — вот кто решает, когда выйти. Выйти из while True иначе никак: break — единственная дверь. Ту же задачу решает и while charge > 0 — обычный while из пятого урока; разница в намерении: while True пишут, когда условие выхода узнаётся внутри цикла, по ходу дела, а не в заголовке.

Обработка потока задач

список задач тает с начала
tasks = ['полить цветы', 'покормить кота', 'выйти']
while True:
    if not tasks:
        print('План пуст')
        break
    task = tasks.pop(0)
    print('Делаю:', task)
Вывод
Делаю: полить цветы
Делаю: покормить кота
Делаю: выйти
План пуст

Список тает с начала: pop(0) достаёт первую задачу. Проверка if not tasks — первая строка тела: список пуст, пора выходить. Здесь условие выхода известно заранее, поэтому честнее заголовок while tasks: — но на практике проверка в теле чаще, потому что условий выхода бывает несколько.

Меню с командой выхода

меню на списке команд
commands = ['привет', 'погода', 'выход', 'анекдот']
while True:
    if not commands:
        break
    command = commands.pop(0)
    if command == 'выход':
        print('До встречи!')
        break
    print('Вы ввели:', command)
Вывод
Вы ввели: привет
Вы ввели: погода
До встречи!

Классика интерфейсов: программа ждёт команду и выполняет её, пока пользователь не попросит выход. В песочнице команды лежат в списке; в настоящей программе их отдаёт input(), и цикл не меняется ни строчкой:

настоящее меню на input()
while True:
    command = input('Команда: ')
    if command == 'выход':
        print('До встречи!')
        break
    print('Вы ввели:', command)
Блок с input() в песочнице не запустится — ввода там нет. Локально это рабочее меню: печатайте команды по одной; на выход программа ответит До встречи! и завершится.

Замените список на input — получите настоящее меню. Заметьте: команда анекдот не выполнилась — break сработал раньше. while True честен: выход есть выход, никакой досмотр после него не делается.

Игра-угадайка

угадай число
secret = 7
guesses = [3, 9, 7]
tries = 0
while True:
    if not guesses:
        print('Попытки кончились')
        break
    guess = guesses.pop(0)
    tries += 1
    if guess == secret:
        print('Угадал за', tries, 'попытки')
        break
    print(guess, '- не то')
Вывод
3 - не то
9 - не то
Угадал за 3 попытки

У игры два события-выхода: игрок угадал или попытки кончились. Оба узнаются только внутри цикла — поэтому заголовок и написан while True. Счётчик tries растёт на каждой попытке: аккумулятор, который здесь же и страховка — попытки не бесконечны.

Главный цикл программы

В настоящей программе while True стоит обычно не внутри, а вокруг всей работы: приём события, обработка, вывод — и снова приём. Выход из такого цикла означает завершение программы целиком, а не выход из одной задачи. Меню, чат-бот, игровой сервер, загрузчик файлов — у всех у них есть этот внешний слой.

Отсюда практическое правило: если программа может завершиться по событию, цикл while True пишется в самом верху, а тело разбивается на небольшие блоки с понятными именами. Иначе через полсотни строк перестаёшь понимать, к какому break относится тот, что стоит на экране.

  • приём события: команды, сообщения, строки из очереди или файла;
  • проверка, не пора ли выходить: очередь пуста, флаг остановки, достигнут потолок итераций;
  • обработка события под try/except, чтобы одна плохая запись не обрывала всю работу;
  • вывод результата и переход к следующему шагу.

В песочнице вместо живого ввода стоит список — так видно ту же структуру, но с предсказуемым результатом. Когда цикл обрастает проверками, счётчик и try/except перестают быть украшением: без них программа либо зависает, либо падает на первом же мусорном значении.

continue: пропуск итерации

У break есть родственник — continue. Он не заканчивает цикл, а бросает остаток текущей итерации: тело начинается заново со следующего шага. В бесконечном цикле continue полезен там, где часть шагов нужно проигнорировать, а само вращение продолжить.

пустые строки пропускаем
log = ['запуск', '', 'ошибка', '', 'останов']

while True:
    if not log:
        print('Лог разобран')
        break
    line = log.pop(0)
    if not line:
        continue
    print('Строка:', line)
Вывод
Строка: запуск
Строка: ошибка
Строка: останов
Лог разобран

Пустые строки пропущены, а цикл не прервался. Разница с break видна на последней строке: после continue программа всё равно дошла до проверки «лог разобран». Правило простое: continue — это «этот шаг не считаем», break — это «всё, выходим».

так выглядит зависание
battery = 60
while True:
    print('Разряд:', battery)
    # battery -= 20 забыли — выхода не будет
Блок не запускается намеренно: в теле нет ни одного break и ни одна переменная не меняется — цикл вечен, программа зависла бы.

Зависание изнутри выглядит скучно: печать повторяет одну и ту же строку бесконечно. Причина — ни break, ни изменение переменной: циклу попросту нечего делать на пути к выходу.

Страховка: лимит итераций

цикл с жёстким потолком
guesses = [3, 9, 5, 4]
attempt = 0
while True:
    if attempt == 3:
        print('Лимит попыток — выход')
        break
    guess = guesses[attempt]
    attempt += 1
    print('Попытка', attempt, ':', guess)
Вывод
Попытка 1 : 3
Попытка 2 : 9
Попытка 3 : 5
Лимит попыток — выход

Профессиональная привычка — ограничивать любой бесконечный цикл сверху: if attempt == 3: break. Даже если нужное событие никогда не наступит, цикл кончится через три итерации. Лимит не заменяет логику — он её страхует: зависание превращается в управляемый выход.

Внешний while True и внутренний for

Смешивать два вида циклов в одной конструкции — обычное дело для настоящей программы: внешний while True крутит «шаг работы», внутренний for перебирает содержимое текущего шага. Разница в том, кто отвечает за выход: внешний цикл — за событие, внутренний — за перебор.

внешний цикл и внутренний перебор
batches = [
    ['отчёт', 'письмо'],
    ['счёт', 'чек'],
]

while True:
    if not batches:
        print('Все пачки разобраны')
        break
    batch = batches.pop(0)
    for item in batch:
        print('Обрабатываю:', item)
Вывод
Обрабатываю: отчёт
Обрабатываю: письмо
Обрабатываю: счёт
Обрабатываю: чек
Все пачки разобраны

Внутренний for отработал обе пачки до конца, а внешний цикл решил, что пора закрываться. Обратите внимание на выход: break во внутреннем for выкинул бы из перебора только одну пачку, а внешний while True продолжил бы крутиться — про двойной выход поговорим ниже.

Как отличить зависание от долгой работы

Программа на while True может и работать, и не работать — снаружи это выглядит одинаково: крутится и не печатает ничего. Различать приходится по месту: добавьте печать на каждой итерации и посмотрите, растёт ли что-то.

отладочная печать показывает прогресс
steps = 0

while True:
    steps += 1
    print('шаг', steps)
    if steps == 3:
        print('дошли до цели')
        break
Вывод
шаг 1
шаг 2
шаг 3
дошли до цели

Если номер шага растёт — цикл работает, просто работает долго. Если шаг застрял на одном и том же значении — тело не меняет состояние, и выхода не будет. Это дешёвый способ отличить «медленно» от «зависло», и он работает лучше, чем перечитывание кода.

break во вложенном цикле

выход только из своего цикла
for floor in [1, 2]:
    for flat in [3, 4]:
        if flat == 4:
            print('Вышли на этаже', floor)
            break
Вывод
Вышли на этаже 1
Вышли на этаже 2

Печатается две строки: break внутри внутреннего цикла вывел только его — внешний продолжил ход по этажам. Вложенные циклы с while True требуют двойного выхода: два break, условие с флагом или вынос внутреннего цикла в отдельную проверку.

Двойной выход: флаг вместо двух break

Классическая задача — найти пару элементов в двух списках и сразу закончить оба перебора. Один break тут не справится, и наивный вариант с ним внутри двух циклов даёт ровно то, чего не хочется: внешний цикл продолжает работать.

поиск пары с флагом
left = ['a', 'b', 'c']
right = ['d', 'b', 'z']

found = False
for x in left:
    for y in right:
        if x == y:
            print('Совпадение:', x)
            found = True
            break
    if found:
        break

print('Поиск закончен, найдено:', found)
Вывод
Совпадение: b
Поиск закончен, найдено: True

Флаг found — булева переменная, которая переживает внутренний цикл. Внутренний break выходит только из перебора right, а проверка if found во внешнем теле выходит уже из перебора left. Один флаг вместо двух break — стандартный приём, когда из вложенной конструкции нужно выйти целиком.

фрагмент: проверка флага на своём месте
found = False
for x in left:
    for y in right:
        if x == y:
            found = True
            break
    if found:      # проверка здесь, а не внутри
        break
Фрагмент: переменные left и right объявлены выше. Отступ на уровне тела внешнего цикла — это то, что прерывает внешний перебор.

Когда while True — лишний

Бесконечный цикл — не признак силы программы, а способ не знать заранее, сколько раз повторять. Если количество повторов известно, while True превращается в балласт: вы пишете break вручную там, где цикл for справился бы сам. Разница в цене — одна лишняя проверка на каждой итерации.

один и тот же результат двумя способами
items = ['a', 'b', 'c']
done = []

while True:
    if not items:
        break
    done.append(items.pop(0))
print(done)

items2 = ['a', 'b', 'c']
done2 = []
for item in items2:
    done2.append(item)
print(done2)
Вывод
['a', 'b', 'c']
['a', 'b', 'c']

Результат одинаковый, и это лучший аргумент в пользу for: он не требует проверки «а не кончилось ли», потому что конец списка известен. Моя практика такая: while True оставляем там, где правда есть событие выхода — команда, ответ, файл, ввод. Всё остальное — for. Если в while True нет ни одного места, где цикл может остановиться по внешнему событию, почти наверняка это просто for, написанный неуверенно.

while условиеwhile True + break
Когда условие известнодо запуска: список, счётчикпо ходу: команда, событие
Читаетсякрутись, пока вернокрутись, пока не скажу стоп
Главный рискусловие не меняется — зависаниеbreak недостижим — зависание
Где уместенперебор данныхменю, игры, серверы, потоки
Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

n = 0
while True:
    n += 2
    if n >= 5:
        print('стоп', n)
        break
words = ['а', 'б', 'в']
while True:
    if not words:
        print('пусто')
        break
    print(words.pop())
n = 3
while True:
    print(n)
    n -= 1
    if n == 1:
        break
Проверь себя
0 / 8

1. Чем завершают цикл while True?

2. Что будет, если в while True нет ни одного break?

3. break стоит внутри внутреннего цикла вложенной конструкции. Что он обрывает?

4. Зачем в while True ставят счётчик-лимит попыток?

5. Как настоящее меню получает команды от пользователя?

6. Чем continue отличается от break?

7. Зачем при выходе из вложенного цикла нужен булев флаг?

8. По какому признаку на месте отличают зависший цикл от долго работающего?

Карточки терминов
Запомнено: 0 / 9
Практика

Соберите обратный отсчёт на while True: заряд = 5; на каждой итерации печатайте Заряд: N и уменьшайте заряд на 1; когда заряд станет нулём — напечатайте Отключение и выйдите через break.

practice.py
Вопросы и ответы по уроку

Зачем нужен бесконечный цикл, если он зависает?

Он не зависает, а ждёт событие: меню крутится, пока пользователь не введёт выход, сервер — пока не получит команду останова. Конец программы определяется событием, а не заголовком цикла, поэтому и пишут while True с break по условию внутри.

Как правильно выйти из while True?

Через break внутри тела: проверить условие выхода — команду, счётчик, флаг — и вызвать break. Правило безопасности: break должен существовать и быть достижимым; для надёжности добавляют лимит итераций.

Урок 6: break

Чем while True отличается от while 1 и от обычного while?

while 1 — то же самое, просто истина записана числом; читается хуже. Обычный while с условием применяется, когда условие выхода известно до запуска; while True — когда событие узнаётся внутри цикла по ходу итерации.

Как остановить бесконечный цикл, если он уже запущен?

Локально — Ctrl+C в терминале: Python прервёт программу с KeyboardInterrupt. В браузерной песочнице — перезагрузить страницу: вечный цикл подвешивает вкладку, поэтому в уроках все блоки завершаются сами.

Урок 5: цикл while

Чем continue отличается от break?

continue пропускает только текущую итерацию: остаток тела не выполняется, цикл продолжается со следующего шага. break прерывает цикл целиком. В бесконечном цикле continue полезен для пропуска ненужных шагов, break — единственный способ выйти.

Как выйти сразу из двух вложенных циклов?

Через булев флаг: внутренний цикл ставит found = True и делает break, а сразу под ним, на уровне тела внешнего цикла, стоит проверка if found: break. Один break прерывает только ближайший цикл — вложенность тут обманчива.

Когда while True лучше обычного цикла for?

Когда у цикла есть внешнее событие выхода, которое наступит неизвестно когда: команда пользователя, ответ сервера, ввод из файла. Если количество повторов известно заранее, for честнее: он сам знает про конец данных, и break вручную не нужен.

Понравился урок? Сошлитесь на него

«Для таких программ цикл пишут наоборот: сначала бесконечный, выход — по событию через break.»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.