Цикл for
Теория
Цикл for перебирает элементы чего-то перебираемого: символы строки, числа из диапазона, а дальше — элементы списков и словарей. На каждой итерации переменная цикла получает следующий элемент, и выполняется тело. Когда элементы кончились — цикл заканчивается сам: в отличие от while, его не нужно останавливать вручную, и бесконечным он не станет.
Для повторения «N раз» и перебора номеров используют range — диапазон целых чисел. Внутри for работают те же break и continue, что и в while. Частый приём — накопление: переменная заводится до цикла и обновляется на каждой итерации (сумма, счётчик, флаг).
Наглядно
Таблица 1. Варианты range и числа, которые он выдаёт. Конец диапазона не входит — как в срезах строк.
| Вызов | Числа | Где пригодится |
|---|---|---|
range(5) |
0, 1, 2, 3, 4 | повторить 5 раз |
range(1, 6) |
1, 2, 3, 4, 5 | номера с единицы |
range(1040, 1045) |
1040 … 1044 | диапазон номеров заказов |
range(0, 10, 2) |
0, 2, 4, 6, 8 | шаг 2 |
range(5, 0, -1) |
5, 4, 3, 2, 1 | обратный отсчёт |
Таблица 2. Когда выбирать for, а когда while.
| Ситуация | Цикл | Пример |
|---|---|---|
| перебрать известный набор | for |
каждый символ артикула, номера заказов из диапазона |
| повторить известное число раз | for + range |
3 платежа рассрочки |
| повторять, пока выполняется условие | while |
повторять оплату до успеха, добавлять товары до бюджета |
На практике
Задача: проверить артикул и промокод посимвольно, вывести номера заказов, рассчитать график рассрочки и разметить ячейки склада.
Шаг 1. Перебираем символы строки
Считаем цифры в артикуле — строка перебирается по символам:
sku = "KB-0142" digits = 0 for ch in sku: if ch.isdigit(): digits += 1 print(digits)
Результат:
4
ch по очереди становится "K", "B", "-", "0"… Метод isdigit() отвечает, состоит ли строка только из цифр. Счётчик digits заведён до цикла — иначе он обнулялся бы на каждой итерации.
Шаг 2. Перебираем числа через range
Выводим номера заказов с 1040 по 1043:
for order_id in range(1040, 1044): print(f"Заказ №{order_id}")
Результат:
Заказ №1040 Заказ №1041 Заказ №1042 Заказ №1043
Чтобы включить 1043, конец диапазона — 1044: range не включает конец.
Шаг 3. Накапливаем результат
График рассрочки: заказ на 4497 ₽ делится на 3 равных платежа, после каждого показываем, сколько выплачено:
total = 4497 months = 3 payment = total // months paid = 0 for month in range(1, months + 1): paid += payment print(f"Месяц {month}: платёж {payment} ₽, выплачено {paid} ₽")
Результат:
Месяц 1: платёж 1499 ₽, выплачено 1499 ₽ Месяц 2: платёж 1499 ₽, выплачено 2998 ₽ Месяц 3: платёж 1499 ₽, выплачено 4497 ₽
Шаг 4. Выходим раньше через break
Промокод допустим, если в нём только буквы и цифры — это проверяет метод isalnum(). Как только встретили недопустимый символ — дальше проверять нет смысла:
code = "SALE-10" is_valid = True for ch in code: if not ch.isalnum(): is_valid = False break print(is_valid)
Результат:
False
Флаг is_valid начинается с True и меняется только при нарушении. Цикл не должен переписывать его на каждой итерации — иначе результат зависел бы только от последнего символа.
Шаг 5. Вкладываем циклы
Разметка склада: на каждом из 2 стеллажей по 3 ячейки. Внутренний цикл проходит целиком для каждой итерации внешнего:
for shelf in range(1, 3): row = "" for cell in range(1, 4): row += f"{shelf}-{cell} " print(row.strip())
Результат:
1-1 1-2 1-3 2-1 2-2 2-3
Всего 2 × 3 = 6 итераций внутреннего тела. Вложенные циклы быстро умножают работу — на больших данных это первое место, где ищут тормоза.
Частые ошибки
- Конец
range.range(1040, 1043)не включает 1043. Нужен «по N включительно» — пишитеrange(a, N + 1). - Накопитель внутри цикла.
total = 0внутри тела обнуляет сумму на каждой итерации — в конце останется только последнее значение. - Флаг переписывается на каждой итерации.
if ok: flag = True else: flag = Falseв цикле — результат зависит только от последнего элемента. Начальное значение — до цикла, внутри — только изменение при «нарушении». - Изменение переменной цикла.
order_id += 1внутриforне пропускает следующий элемент — на следующей итерацииforвсё равно присвоит очередное значение. Для пропуска —continue. whileсо счётчиком вместоfor. Ручной счётчик — лишний шанс ошибиться на единицу или зациклиться; для известного числа повторов —forиrange.
Итог
Как работает for
for x in что-то:—xпо очереди принимает каждый элемент; цикл заканчивается сам.- Строка перебирается по символам; дальше так же перебираются списки и словари.
range
range(n)— 0…n-1;range(a, b)— a…b-1;range(a, b, шаг), шаг может быть отрицательным.- Конец не входит: «по N включительно» —
range(a, N + 1).
Приёмы
- Накопление: переменная — до цикла, обновление — в теле.
- Флаг: начальное значение до цикла, внутри — изменение и
break. breakиcontinueработают так же, как вwhile.- Вложенные циклы: внутренний проходит полностью на каждой итерации внешнего.
Вопросы на собеседовании
Почему range(1, 10) не включает 10?
Полуоткрытые интервалы [начало, конец) — общее правило Python (так же работают срезы). Длина диапазона равна конец - начало, а соседние диапазоны range(0, 5) и range(5, 10) стыкуются без пересечений и пропусков.
Можно ли пропустить элемент, изменив переменную цикла for внутри тела?
Нет. На каждой итерации for сам присваивает переменной следующий элемент, поэтому изменение внутри тела действует только до конца текущей итерации. Пропустить элемент можно через continue.
Сколько памяти занимает range(1_000_000)?
Почти нисколько: range не хранит числа, а вычисляет их по запросу из начала, конца и шага. Поэтому большой диапазон не создаёт миллион объектов.
Глубже
Что на самом деле делает for — протокол итерации, iter() и next() — в курсе «Python под капотом», тема «Как работает for».