💻
Разработка в IT
Опубликовано:
14.04.2026
Обновлено:
14.04.2026

Бесконечные циклы в Python: причины и способы избежать

Алексей Иванов

Первый баг в моей практике на Python случился из-за пропущенной строки n = n - 1 внутри while. Терминал завис, вентилятор ноутбука раскрутился, и пришлось жать Ctrl+C. Бесконечный цикл, или infinite loop, возникает, когда условие выхода из цикла никогда не становится ложным. Python продолжает выполнять тело цикла снова и снова, пока процесс не будет прерван вручную.

Эта статья разбирает причины появления бесконечных циклов, показывает типовые ошибки на конкретных примерах кода и объясняет, когда while True полезен, а когда опасен.

Что такое бесконечный цикл и почему он возникает

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

Цикл while проверяет условие перед каждой итерацией. Если после выполнения тела условие по-прежнему True, цикл запускает тело заново. Ни одна проверка не происходит в середине тела: Python завершает текущую итерацию и только потом сравнивает условие.

Как выглядит простой бесконечный цикл

Классический пример из обучения Python: обратный отсчёт с ошибкой.

n = 5
while n > 0:
    print(n)
    # Забыли n = n - 1
    # Цикл напечатает 5 бесконечно

Переменная n никогда не уменьшается, условие n > 0 всегда истинно. Исправление одной строкой:

n = 5
while n > 0:
    print(n)
    n = n - 1
print('Готово!')
# Вывод: 5, 4, 3, 2, 1, Готово!

Пять причин появления бесконечных циклов

Разберём типовые сценарии, при которых цикл не завершается.

Итерационная переменная не обновляется

Самая частая причина. Программист создаёт переменную-счётчик, задаёт условие, но забывает изменить счётчик внутри тела.

i = 0
while i < 10:
    print(i)
    # i += 1 отсутствует

Переменная i остаётся равной 0 на каждой итерации. Решение: добавить i += 1 в конце тела цикла.

Условие написано с логической ошибкой

Условие может содержать ошибку в операторе сравнения или логической связке.

x = 10
while x > 0 or x < 100:
    x -= 1
    print(x)

Условие x > 0 or x < 100 истинно при любом значении x, потому что x < 100 остаётся True даже при отрицательных числах. Программист хотел написать and вместо or:

x = 10
while x > 0 and x < 100:
    x -= 1
    print(x)

Обновление переменной в неправильной ветке if

Когда тело цикла содержит условные конструкции, обновление счётчика может оказаться внутри ветки, которая не всегда выполняется.

count = 0
target = 5
while count < target:
    value = int(input('Число: '))
    if value > 0:
        count += 1
        print(f'Принято: {count}/{target}')
    # Если value <= 0, count не растёт

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

Мутация коллекции во время итерации

Добавление элементов в список, по которому идёт цикл, создаёт бесконечный рост.

items = [1, 2, 3]
i = 0
while i < len(items):
    items.append(items[i] + 1)  # список растёт быстрее, чем i
    i += 1

На каждой итерации len(items) увеличивается на 1, и i никогда не догонит длину. Решение: зафиксировать длину перед циклом.

items = [1, 2, 3]
length = len(items) 	# фиксируем
i = 0
while i < length:
    items.append(items[i] + 1)
    i += 1
print(items) # [1, 2, 3, 2, 3, 4]

Рекурсия без базового случая

Формально это не while-цикл, но эффект тот же: функция вызывает сама себя без условия остановки.

def countdown(n):
    print(n)
    countdown(n - 1)  # нет проверки n <= 0


countdown(5)
# 5, 4, 3, 2, 1, 0, -1, -2 ... RecursionError

Python ограничивает глубину рекурсии (по умолчанию 1000 вызовов), поэтому программа не зависнет навсегда, но завершится аварийно. Добавим базовый случай:

def countdown(n):
    if n <= 0:
        print('Готово!')
        return
    print(n)
    countdown(n - 1)

Когда while True оправдан

Конструкция while True создаёт намеренный бесконечный цикл. Выход из него происходит через break при выполнении определённого условия. Три ситуации, где while True удобен.

Чтение ввода до сигнала остановки

while True:
    line = input('> ')
    if line == 'done':
        break
    print(line)
print('Завершено!')

Цикл принимает ввод, пока пользователь не напечатает done. Оператор break прерывает цикл, управление переходит к строке после while.

Повторение до получения корректных данных

while True:
    try:
        age = int(input('Возраст: '))
        if 0 < age < 150:
            break
        print('Возраст вне диапазона 1-149')
    except ValueError:
        print('Введите целое число')

print(f'Ваш возраст: {age}')

Блок try/except внутри while True перехватывает ошибку преобразования. Цикл повторяется, пока пользователь не введёт корректное число.

Серверный цикл обработки

import socket


server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 9999))
server.listen(1)


while True:
    conn, addr = server.accept()
    data = conn.recv(1024)
    if not data:
        break
    conn.sendall(data)
    conn.close()

Сервер ожидает подключения в бесконечном цикле. Без while True пришлось бы заранее знать число подключений.

Как управлять бесконечным циклом: break, continue, флаги

Python предоставляет три механизма управления.

break заставляет Python немедленно выйти из ближайшего цикла. Строки после break внутри тела не выполняются. Управление переходит к первой строке после блока while.

continue пропускает оставшуюся часть тела и возвращается к проверке условия. Подходит для фильтрации нежелательных данных.

while True:
    line = input('> ')
    if line == 'done':
        break
    if line[0] == '#':
        continue  # пропускаем комментарии
    print(line)

Флаговая переменная. Вместо break можно использовать переменную-флаг.

running = True
while running:
    command = input('Команда: ')
    if command == 'exit':
        running = False
    else:
        print(f'Выполняю: {command}')

Когда цикл завершает итерацию и проверяет running, значение уже False, и цикл останавливается.

Подход

Читаемость

Гибкость

Когда применять

break

Высокая

Средняя

Один момент выхода

continue

Средняя

Средняя

Фильтрация внутри цикла

Флаг

Высокая

Высокая

Несколько точек выхода, дочистка до конца итерации

return

Высокая

Высокая

Цикл внутри функции

Как обнаружить бесконечный цикл при отладке

Если программа зависла, есть несколько способов диагностики.

  1. Добавить отладочный print внутри тела цикла с выводом значения условной переменной.
  2. Установить аварийный счётчик с лимитом итераций и break при превышении.
  3. Использовать таймаут через модуль signal (Unix) или threading.Timer.
  4. Запустить пошаговое выполнение через pdb.set_trace() и наблюдать за переменными.
# Аварийный счётчик
max_iterations = 10_000
count = 0
while some_condition:
    count += 1
    if count > max_iterations:
        print('Превышен лимит итераций!')
        break

# Таймаут через signal (Unix)
import signal


def handler(signum, frame):
    raise TimeoutError('Цикл работает слишком долго')


signal.signal(signal.SIGALRM, handler)
signal.alarm(5)  # 5 секунд

try:
    while True:
        pass
except TimeoutError as e:
    print(e)

Конструкция while-else и её связь с break

Python поддерживает блок else после while. Код в else выполняется только если цикл завершился естественно (условие стало False). Если цикл прерван через break, блок else пропускается.

n = 5
while n > 0:
    if n == 3:
        print('Нашли 3, прерываем')
        break
    n -= 1
else:
    print('Цикл завершился полностью')

# Вывод: Нашли 3, прерываем
# else-блок НЕ выполнился

Эта конструкция полезна при поиске элемента: если break сработал, элемент найден; если нет, else сообщает об отсутствии.

Бесконечный цикл for: возможен ли

Цикл for в Python итерирует по конечной последовательности, поэтому бесконечным стать не может, если итерируемый объект конечен. Но бесконечные итераторы существуют.

import itertools


# itertools.count() - бесконечный счётчик
for i in itertools.count(0):
    if i > 50:
        break
    print(i)

# itertools.cycle() - бесконечное повторение
for item in itertools.cycle([1, 2, 3]):
    print(item)
    if item == 3:
        break

Функции count(), cycle() и repeat() из itertools создают бесконечные итераторы. Без break внутри for такой цикл не остановится.

Генератор с yield без условия выхода тоже бесконечен:

def infinite_counter(start=0):
    n = start
    while True:
        yield n
        n += 1


for i in infinite_counter():
    if i > 100:
        break
    print(i)

Пошаговая проверка: как убедиться, что цикл завершится

Чек-лист перед запуском кода с while:

  1. Определите итерационную переменную, от которой зависит условие.
  2. Убедитесь, что переменная изменяется внутри тела цикла.
  3. Проверьте, что изменение приближает переменную к нарушению условия.
  4. Проверьте крайние случаи: нулевое значение, отрицательное число, пустой список.
  5. Если в теле есть if/else, убедитесь, что переменная обновляется во всех ветках.
  6. Добавьте аварийный счётчик на время разработки.
  7. Протестируйте цикл с граничными данными перед удалением защитного счётчика.

Неочевидные факты о бесконечных циклах

Первый: CPython компилирует while True и while 1 в одинаковый байт-код. Разницы в производительности нет.

Второй: Ctrl+C вызывает KeyboardInterrupt, но если цикл перехватывает все исключения через bare except:, прервать его стандартным способом не получится. Правильный вариант: except Exception:, который пропускает KeyboardInterrupt и SystemExit.

# Опасно:
while True:
    try:
        pass
    except:  # перехватывает ВСЁ, включая KeyboardInterrupt
        pass

# Безопасно:
while True:
    try:
        pass
    except Exception:  # KeyboardInterrupt пройдёт
        pass

Третий: бесконечный цикл с time.sleep() внутри не потребляет 100% процессора. Без sleep() один поток Python загрузит одно ядро полностью.

Четвёртый: itertools.count и itertools.cycle написаны на C и работают быстрее, чем аналогичный while True с yield на чистом Python.

FAQ

Как остановить бесконечный цикл втерминале?

Нажмите Ctrl+C. Python перехватитсигнал SIGINT и выбросит KeyboardInterrupt. Еслипрограмма запущена в фоне, найдитепроцесс через ps aux | grep python и завершитекомандой kill.

Можно ли использовать while True в продакшене?

Да.Серверы, демоны, воркеры очередейработают в бесконечном цикле. Главное:предусмотреть корректное завершениечерез обработку сигналов (SIGTERM, SIGINT) иосвобождение ресурсов.

Чем breakотличается от sys.exit()?

break выходитиз текущего цикла, выполнение продолжаетсяпосле while. sys.exit() завершает всюпрограмму. Если вложено двацикла, break выходит только извнутреннего.

Почемуfor i in range() не бываетбесконечным?

Функция range() создаётконечную последовательность. Аргументыstart, stop, step определяют границы. Даже range(0,10**18) конечен, хотя итерация займётгоды.

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

Технически да, но Pythonограничивает глубину рекурсии(sys.getrecursionlimit(), по умолчанию 1000). Длядлительной работы используйте whileTrue, а не рекурсию.

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

Читайте также