Программа зависла: как найти и остановить бесконечный цикл

Ошибки Pythonобновлено 07.10.20269 мин чтенияесть тренажёр

Бесконечный цикл — это цикл, условие которого никогда не становится ложным, поэтому программа повторяет одно и то же без остановки. Чаще всего забыли изменить переменную в теле while, счётчик идёт не в ту сторону или в while True нет break. Остановить программу можно сочетанием Ctrl+C.

Загружаем…

Что такое бесконечный цикл

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

Здесь главное отличие от остальных страниц раздела. При NameError или IndexError Python печатает сообщение и останавливается сам. Ни в официальной документации Python, ни в списке встроенных исключений нет отдельной ошибки для зацикливания: распознать его должен сам программист. При зацикливании сообщения нет: программа либо бесконечно печатает одно и то же, либо молча «думает», и кажется, что компьютер завис. Запустите код в редакторе выше. Он должен отсчитать от 5 до 1 и вывести «Пуск!», но пятёрки будут сыпаться без конца, пока не сработает ограничение времени — защита редактора от зависания. После этого под выводом появится сообщение и подсказка.

otschet = 5
while otschet > 0:
    print(otschet)
print("Пуск!")

Переменная otschet равна 5 и внутри цикла не меняется. Условие «5 больше 0» истинно сейчас, будет истинно через секунду и через час. Исправление — одна строка в теле цикла: otschet -= 1. Тогда на каждом шаге значение уменьшится, и после единицы условие станет ложным. В официальной документации Python оператор while описан именно так: тело повторяется, пока выражение в заголовке истинно. Как устроен сам оператор while, подробно рассказано в уроке про цикл while в Python.

otschet = 5
while otschet > 0:
    print(otschet)
    otschet -= 1
print("Пуск!")

Почему цикл не останавливается: 5 причин

Зацикливание почти всегда объясняется одной из 5 причин. Шаги цикла при этом выглядят одинаково, и все причины сводятся к вопросу: что внутри тела цикла меняет переменную из условия?

ПричинаКак выглядитКак исправить
Счётчик не меняетсяВ теле нет i += 1Добавить изменение в конец тела
Счётчик идёт не тудаwhile i > 0: и i += 1Сменить знак шага или условие
Граница перепрыгнутаwhile x != 10: при шаге 2 от 1Использовать < вместо !=
Изменение вне телаi += 1 без отступа, после циклаСдвинуть строку внутрь блока
Нет выхода из while TrueНет break или условие для него не выполняетсяПроверить ветку с break

Первая строка таблицы — самый простой случай зацикливания: достаточно дописать одну команду. Четвёртая причина коварна тем, что строка с изменением есть, и глаз её видит. Но без отступа она стоит после цикла и выполнится, только когда цикл закончится, а он не закончится никогда. Это тот случай, когда отступ меняет смысл программы. Руководство PEP 8 требует 4 пробела на уровень[1]: ровный отступ помогает сразу увидеть, какие строки внутри тела.

Граница, которую цикл перепрыгнул

Условие с != опасно, если переменная меняется шагом больше 1: она может проскочить нужное значение и уйти дальше. Тогда цикл без конца ищет число, которого уже никогда не будет.

x = 1
while x != 10:
    x += 2
print(x)

Шаги идут через один: переменная принимает значения 1, 3, 5, 7, 9, 11, 13… Десятки среди них нет: все числа нечётные. Условие «x не равно 10» остаётся истинным вечно. Такое зацикливание трудно заметить на глаз: код выглядит аккуратно. Исправление — сравнивать с запасом: while x < 10:. Тогда цикл остановится на первом значении, которое больше или равно 10, то есть на 11.

x = 1
while x < 10:
    x += 2
print(x)

Этот приём полезно запомнить на будущее: в условии продолжения лучше писать <, >, <=, >=, а не !=, если только переменная не меняется ровно на 1. С дробными числами строгое равенство тем более не стоит использовать: из-за погрешности вычислений результат может отличаться от ожидаемого в последнем знаке.

Когда while True — это нормально

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

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

summa = 0
while True:
    slovo = input("Число или стоп: ")
    if slovo == "стоп":
        break
    summa += int(slovo)
print("Сумма:", summa)

Такой цикл безопасен, только если до break действительно можно дойти. Документация Python описывает break как немедленный выход из ближайшего цикла: остальные шаги тела уже не выполняются. Типичная ошибка — проверка на «Стоп» с большой буквы, а пользователь вводит «стоп»; или input() стоит до цикла, и введённое слово больше не меняется. В Scratch такому циклу соответствует блок «повторять всегда»: игра должна работать, пока её не остановят красной кнопкой. В Python для игр и анимаций черепашкой тоже используют цикл без конца, но с понятным способом выхода. Ещё несколько примеров с break и continue собраны в материале с задачами на циклы.

«Бесконечный цикл — всегда ошибка программиста». Это миф: игры, меню и анимации намеренно работают без конца, а в Scratch для этого есть отдельный блок. Ошибка — только цикл без задуманного выхода.

«Цикл for не может быть бесконечным». Это не подтверждается: если в теле for x in spisok добавлять элементы в тот же список, перебор никогда не закончится. Цикл по range() действительно конечен, но перебор изменяемого списка — нет.

Как остановить зависшую программу

Чтобы остановить программу, которая крутится без конца, нажмите Ctrl+C в окне, где она запущена. Python прервёт выполнение и напишет KeyboardInterrupt — это не ошибка кода, а след нажатия.

  • Терминал или командная строка. Ctrl+C прерывает программу. Если она ждёт ввода, иногда нужно нажать ещё раз.
  • IDLE. Ctrl+C в окне Shell или пункт меню Shell → Interrupt Execution. Если не помогло — Shell → Restart Shell.
  • Редактор на нашем сайте. Делать ничего не нужно: ограничение времени работы само остановит выполнение и покажет подсказку.
  • Scratch. Красный восьмиугольник «Стоп» рядом с зелёным флажком останавливает все скрипты.

Закрывать окно редактора кода с несохранённым файлом не стоит: остановка через Ctrl+C сохраняет и программу, и всё, что она успела вывести. По выводу как раз удобно искать причину. Установка Python и знакомство с IDLE описаны в статье про установку Python.

Как найти место зацикливания

Если программа длинная и непонятно, какой цикл виноват, помогут 3 приёма: отладочный вывод, предохранитель и ручная трассировка на бумаге.

Отладочный вывод в теле цикла

Добавьте в начало тела строку print() со значениями переменных из условия. Если шаги повторяют одно и то же значение снова и снова, вы нашли и цикл, и переменную, которая не меняется.

i = 0
while i < 3:
    print("шаг", i, "условие", i < 3)
    i += 1

Счётчик-предохранитель

На время отладки можно ограничить число повторений: завести переменную shagov, увеличивать её на каждом шаге и прерывать цикл после, например, 1000 повторов с сообщением. Так программа не будет крутиться вечно, а вы увидите, что граница достигнута. После исправления предохранитель лучше убрать, чтобы он не маскировал настоящую логику.

x = 1
shagov = 0
while x != 10:
    x += 2
    shagov += 1
    if shagov > 1000:
        print("Слишком много шагов, x =", x)
        break

Третий приём — трассировочная таблица: столбцы для каждой переменной и условия, строки для шагов. Её рисуют на уроках информатики, и для поиска такой ошибки она особенно хороша: уже на 3–4 строке видно, что значение не приближается к границе. Больше способов искать ошибки описано в статье об отладке программ.

Когда совет «добавь break» не поможет

Добавить break наугад не поможет, если цикл крутится из-за неверной логики. В этих 4 случаях нужно менять условие или тело цикла.

  • Break стоит во вложенном цикле. Он прерывает только 1 внутренний цикл, а внешний while продолжает работать.
  • Условие для break зависит от ввода, который читается 1 раз до цикла. Перенесите input() внутрь тела.
  • Сравнение строки с числом. input() возвращает строку, и проверка slovo == 0 не выполнится ни на 1 шаге. Нужно int(slovo) == 0.
  • Цикл перебирает список, который растёт. Каждый шаг добавляет 1 новый элемент, и break до конца не доберётся — нужен второй список для результата.

Чего делать нельзя

Нельзя запускать программу снова и снова в надежде, что «в этот раз остановится»: без изменений в коде цикл поведёт себя точно так же.

  • Нельзя писать while True без продуманного выхода через break или return.
  • Не следует сравнивать через !=, если переменная меняется шагом больше единицы.
  • Не стоит менять переменную условия вне тела цикла — проверяйте отступ у строки с += 1.
  • Не допускается добавлять элементы в список, который перебирает этот же цикл.
  • Не стоит оставлять в готовой программе отладочные print и предохранители.
  • Нельзя проверять равенство дробных чисел в условии цикла: из-за округления оно может не выполниться никогда.

Если программа не крутится вечно, а падает с сообщением, разберите его по шагам из статьи как читать ошибки Python.

Источники

[1] van Rossum G., Warsaw B., Coghlan N. PEP 8 — Style Guide for Python Code. Python Software Foundation, 2001.

[2] The Python Tutorial (официальная документация Python 3). Python Software Foundation. — синтаксис и встроенные функции.

[3] Приказ Минпросвещения России от 18.05.2023 № 370 «Об утверждении федеральной образовательной программы основного общего образования». — информатика 7–9 (см. факты).

Вопросы и ответы

Может ли бесконечный цикл сломать компьютер?

Нет. Он только занимает процессор, пока работает. После Ctrl+C или закрытия окна всё возвращается в норму. Осторожнее с циклами, которые копят данные в список: они могут занять много памяти.

Что значит KeyboardInterrupt?

Это сообщение о том, что программу прервали с клавиатуры, обычно сочетанием Ctrl+C. Исправлять тут нечего, но строка в сообщении покажет, где программа была в момент остановки.

Почему в редакторе сайта программа обрывается сама?

Там действует ограничение времени работы: если программа выполняется слишком долго, редактор её останавливает. Это защита вкладки браузера: без неё страница перестала бы отвечать.

Чем while отличается от for в смысле остановки?

for перебирает готовую последовательность, и по range() он всегда конечен. while работает, пока условие истинно, поэтому за его выходом нужно следить самому. Подробности — в официальной документации Python[2].

Изучают ли циклы с условием в школе?

Да, по федеральной образовательной программе циклы с условием и с переменной входят в курс информатики 8 класса[3]. Трассировочные таблицы там же помогают искать ошибки в циклах.

Есть ли в Scratch бесконечный цикл?

Да, это блок «повторять всегда». Для игр он нужен: персонаж должен реагировать на клавиши всё время, пока работает проект. Останавливают его кнопкой «Стоп».