💻 Практические примеры

⚡ Шпаргалка: while в двух экранах кода

total = 0
while True:
    n = int(input("Number (0 to stop): "))
    if n == 0:
        break
    total += n
print(total)
КонструкцияЧто делает
while условие:повторяет тело, пока условие истинно (проверка перед каждой итерацией)
breakнемедленно завершает цикл целиком
continueпропускает остаток текущей итерации, переходит к проверке условия
while ... else:else выполняется, только если цикл завершился без break
while True:бесконечный цикл; единственный выход — break внутри тела
Топ-3 ошибки: забыли изменить переменную цикла → цикл не заканчивается · инкремент стоит после continue и не выполняется на пропущенных итерациях · перепутали break (выход из цикла) с continue (пропуск итерации).

Примеры идут от простого к сложному: сначала базовый счётчик, затем накопление результата, ловушка бесконечного цикла, управление итерациями через break/continue, блок else, сравнение с for, обработка пользовательского ввода и, наконец, реальная защита от зависания на игре «Угадай число». Весь вывод в комментариях получен реальным запуском кода.

Пример 1. Счётчик от 1 до 5

Классический счётчик — основа темы: инициализация переменной, условие и изменение переменной внутри тела цикла.

📄 examples/counter.py
i = 1
while i <= 5:
    print(i)
    i += 1
# 1
# 2
# 3
# 4
# 5

Что происходит: i начинается с 1. Перед каждой итерацией Python проверяет условие i <= 5; пока оно истинно — выполняется тело, затем i += 1 увеличивает счётчик. Когда i становится 6, условие ложно, и цикл завершается.

Пример 2. Накопление результата: сумма и список за один проход

Частая задача — не просто перебрать значения, а накопить из них результат: сумму, список отобранных элементов, счётчик совпадений. Здесь while перебирает список по индексу.

📄 examples/accumulate.py
values = [4, -2, 9, 0, 5, -7, 3]
i = 0
total = 0
positives = []

while i < len(values):
    if values[i] > 0:
        total += values[i]
        positives.append(values[i])
    i += 1

print("Total of positives:", total)
print("Positives list:", positives)
# Total of positives: 21
# Positives list: [4, 9, 5, 3]

Что происходит: i играет роль индекса и условия остановки одновременно (i < len(values)). На каждой итерации в total накапливается сумма, а в positives — список отобранных элементов. И то, и другое — это переменные-аккумуляторы: их создают до цикла и обновляют внутри тела.

Пример 3. Ловушка бесконечного цикла — забыли изменить переменную

Самая частая ошибка новичка: условие есть, а переменная, от которой оно зависит, внутри тела не меняется. Показываем эффект безопасно — с защитным лимитом итераций, а не реальным зависанием.

📄 examples/infinite_trap.py
i = 0
attempts = 0
MAX_ITERATIONS = 5  # защитный лимит — в реальной ловушке i += 1 отсутствует,
                     # поэтому i < 3 никогда не станет ложным

while i < 3:
    print("iteration", attempts)
    attempts += 1
    if attempts >= MAX_ITERATIONS:
        print("Forgot to update i! Breaking out after", attempts, "iterations to avoid a real infinite loop.")
        break
    # i += 1  # <- без этой строки i никогда не достигнет 3 само по себе

# iteration 0
# iteration 1
# iteration 2
# iteration 3
# iteration 4
# Forgot to update i! Breaking out after 5 iterations to avoid a real infinite loop.

Почему так: условие i < 3 зависит только от i, а i в теле не меняется — без страховки цикл выполнялся бы вечно. В учебном примере роль страховки играет счётчик attempts с break; в реальном коде страховка не нужна — нужно просто не забыть обновить переменную цикла (см. Ошибку 1).

Пример 4. break: досрочный выход по сигналу

break прерывает цикл целиком, даже если условие всё ещё истинно. Классическое применение — стоп-слово в потоке значений. Вместо input() вводы смоделированы списком, чтобы пример гарантированно завершался сам.

📄 examples/break_demo.py
inputs = iter(["10", "25", "stop", "999"])

total = 0
while True:
    value = next(inputs)
    if value == "stop":
        print("Stopped by user command.")
        break
    total += int(value)

print("Sum before stop:", total)
# Stopped by user command.
# Sum before stop: 35

Что происходит: while True — намеренно бесконечный цикл: заранее неизвестно, сколько значений придёт. break — единственный способ из него выйти, и он срабатывает по стоп-слову "stop". Значение "999" после стоп-слова уже не читается — цикл завершился раньше.

Пример 5. continue: пропуск одной итерации

continue не завершает цикл — он пропускает только оставшуюся часть текущей итерации и возвращается к проверке условия.

📄 examples/continue_demo.py
numbers = [5, -3, 8, -1, 2]
i = 0
total = 0

while i < len(numbers):
    n = numbers[i]
    i += 1
    if n < 0:
        continue
    total += n

print("Sum of non-negative numbers:", total)
# Sum of non-negative numbers: 15

Почему так: i += 1 стоит до проверки continue, поэтому индекс продвигается на каждой итерации независимо от того, сработал continue или нет. Если бы инкремент стоял после проверки, отрицательное число вызвало бы бесконечный цикл — это разбирается в Ошибке 4.

Пример 6. while ... else: когда выполняется, а когда нет

Блок else у цикла выполняется только при естественном завершении — когда условие стало ложным. Если цикл прервал break, else пропускается. Один и тот же поиск, два исхода.

📄 examples/while_else_demo.py
values = [1, 2, 3, 4, 5]

target = 4
i = 0
while i < len(values):
    if values[i] == target:
        print(f"Found {target} at index {i}")
        break
    i += 1
else:
    print(f"{target} was not found")
# Found 4 at index 3

target2 = 9
i = 0
while i < len(values):
    if values[i] == target2:
        print(f"Found {target2} at index {i}")
        break
    i += 1
else:
    print(f"{target2} was not found")
# 9 was not found

Что происходит: для target = 4 элемент найден, сработал break — блок else не выполняется, строка про «не найдено» не печатается. Для target2 = 9 цикл дошёл до конца списка без break — условие i < len(values) стало ложным естественно, и else выполнился. continue на else не влияет: он не прерывает цикл, поэтому если после него цикл всё же доработает до конца, else выполнится как обычно.

Пример 7. while и for: когда что уместнее

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

📄 examples/while_vs_for.py
# for: число шагов известно заранее — три дня, и точка
for day in range(1, 4):
    print(f"Day {day}: watering the plant")
# Day 1: watering the plant
# Day 2: watering the plant
# Day 3: watering the plant

# while: продолжаем, пока не выполнится условие — число шагов заранее не известно
water_level = 10
day = 0
while water_level > 0:
    day += 1
    water_level -= 3
    print(f"Day {day}: water level = {water_level}")
# Day 1: water level = 7
# Day 2: water level = 4
# Day 3: water level = 1
# Day 4: water level = -2

Правило выбора: если заранее известно, сколько раз повторить действие (по списку, по range) — используйте for, он короче и не даёт забыть про изменение переменной. Если цикл должен идти, пока выполняется какое-то условие, а число повторений заранее неизвестно (ждём ввод, ждём события, копим до порога) — нужен while. Подробный разбор for — в уроке 16 «Цикл for».

Пример 8. Валидация ввода: цикл до получения корректного значения

Частый шаблон: запрашивать данные, пока пользователь не введёт то, что нужно. Вместо реального input() вводы смоделированы списком — так пример не зависит от stdin и гарантированно завершается.

📄 examples/validate_input.py
fake_inputs = iter(["abc", "-5", "42"])  # смоделированная последовательность вводов

while True:
    raw = next(fake_inputs)
    if not raw.lstrip("-").isdigit():
        print(f"'{raw}' is not a number, try again")
        continue
    number = int(raw)
    if number < 0:
        print(f"{number} is negative, try again")
        continue
    break

print("Accepted number:", number)
# 'abc' is not a number, try again
# -5 is negative, try again
# Accepted number: 42

Что происходит: while True запрашивает значение снова и снова; continue возвращает к следующей попытке при некорректном вводе; break выходит из цикла, как только значение прошло обе проверки. В реальном скрипте вместо next(fake_inputs) будет input(...) — логика проверки не изменится.

⚠️ Проверить по документации: оператор «морж» := (Python 3.8+) позволяет присвоить значение и сразу проверить условие в одной строке (while (raw := input()) != "stop":) — современная альтернатива ручному чтению внутри while True. В лекции он упомянут как «на заметку»; сверьтесь с Assignment Expressions.

Пример 9. Реальная защита от бесконечного цикла: лимит попыток в игре «Угадай число»

В играх с угадыванием пользователь может никогда не ввести правильный ответ — без лимита попыток цикл действительно был бы бесконечным. Ограничение числа попыток — это и есть защита, а не просто демонстрация. Для воспроизводимости вывода используется random.seed, а вводы игрока смоделированы списком.

📄 examples/guess_number_limited.py
import random

random.seed(7)
secret = random.randint(1, 10)
guesses = iter([3, 8, 6])  # смоделированные попытки игрока
max_attempts = 3
attempts_used = 0

while attempts_used < max_attempts:
    guess = next(guesses)
    attempts_used += 1
    if guess == secret:
        print(f"Guessed correctly in {attempts_used} attempts!")
        break
    hint = "greater" if guess < secret else "less"
    print(f"Attempt {attempts_used}: the secret number is {hint}")
else:
    print(f"Out of attempts. The secret number was {secret}.")
# Attempt 1: the secret number is greater
# Attempt 2: the secret number is less
# Guessed correctly in 3 attempts!

Что происходит: условие цикла attempts_used < max_attempts само по себе и есть защита от зависания — даже если guess никогда не совпадёт с secret, цикл остановится после max_attempts попыток и выполнит else. Полная версия игры с вводом через input() и оценкой результата — в разделе 🏠 Домашнее задание.

Пример 10. Модуль random: случайные числа для игр и симуляций

random — модуль стандартной библиотеки, без него не обходится ни один пример со случайным числом, включая игру из примера 9. random.seed() делает «случайный» вывод повторяемым — удобно для обучения и отладки.

📄 examples/random_demo.py
import random

random.seed(42)
print("Random float:", random.random())
print("Dice roll:", random.randint(1, 6))
print("Random step:", random.randrange(0, 101, 10))
# Random float: 0.6394267984578837
# Dice roll: 1
# Random step: 40

Что происходит: random.random() возвращает float в диапазоне [0.0, 1.0), random.randint(a, b) — целое число, включая обе границы, random.randrange(start, stop, step) — целое из диапазона как у range. Без random.seed(42) вывод менялся бы при каждом запуске; с ним — воспроизводим один и тот же результат.

Как запустить в VS Code

  1. Создайте файл example.py в папке урока.
  2. Скопируйте код из примера выше.
  3. Откройте терминал в VS Code (Ctrl + `).
  4. Убедитесь, что активировано виртуальное окружение: venv\Scripts\activate (Windows) или source venv/bin/activate (Mac/Linux).
  5. Запустите: python example.py