Примеры идут от простого к сложному: сначала базовый счётчик, затем накопление результата, ловушка бесконечного цикла, управление итерациями через break/continue, блок else, сравнение с for, обработка пользовательского ввода и, наконец, реальная защита от зависания на игре «Угадай число». Весь вывод в комментариях получен реальным запуском кода.
Пример 1. Счётчик от 1 до 5
Классический счётчик — основа темы: инициализация переменной, условие и изменение переменной внутри тела цикла.
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 перебирает список по индексу.
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. Ловушка бесконечного цикла — забыли изменить переменную
Самая частая ошибка новичка: условие есть, а переменная, от которой оно зависит, внутри тела не меняется. Показываем эффект безопасно — с защитным лимитом итераций, а не реальным зависанием.
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() вводы смоделированы списком, чтобы пример гарантированно завершался сам.
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 не завершает цикл — он пропускает только оставшуюся часть текущей итерации и возвращается к проверке условия.
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 пропускается. Один и тот же поиск, два исхода.
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: когда что уместнее
Оба цикла перебирают, пока условие/последовательность не закончатся, но выбор зависит от того, известно ли заранее число повторений.
# 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 и гарантированно завершается.
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, а вводы игрока смоделированы списком.
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() делает «случайный» вывод повторяемым — удобно для обучения и отладки.
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
- Создайте файл
example.pyв папке урока. - Скопируйте код из примера выше.
- Откройте терминал в VS Code (Ctrl + `).
- Убедитесь, что активировано виртуальное окружение:
venv\Scripts\activate(Windows) илиsource venv/bin/activate(Mac/Linux). - Запустите:
python example.py