range в Python: цикл со счётчиком
range делает цикл for счётчиком: n повторов от нуля, диапазон от начала до конца, шаг и обратный отсчёт. Разбираем все три формы range на примерах с запуском.
Редакция Питоники
Цикл из первого урока ходил по готовым данным: список гостей, список шагов. Но половина повторов в программах — не данные, а счёт: сделать 5 повторов, пронумеровать страницы от 1 до 10, посчитать секунды до запуска. Создавать список чисел руками ради цикла странно. Для этого в Python есть range — встроенный генератор числовых последовательностей, главный способ управлять счётчиком цикла for.
range(n): n шагов от нуля
Простейшая форма — один аргумент: range(n) даёт циклу n чисел, начиная с нуля:
for i in range(5):
print(i)
0 1 2 3 4
Пять чисел — от 0 до 4. Пятёрки в переборе нет: range(5) — это «пять шагов, нумерация с нуля», а не «числа до пяти». range(n) делает ровно n шагов: числа идут от 0 до n-1, а само число n не входит. Такое соглашение выглядит непривычно, но у него есть скрытая аккуратность: сколько чисел заказали, столько шагов и получили — без единицы сверху. В переменную i на каждом шаге попадает очередной номер: 0, 1, 2 и так далее.
for i in range(3):
print(f'Повтор номер {i}')
Повтор номер 0 Повтор номер 1 Повтор номер 2
range — это не список
Первое, что стоит понять про range: это не список чисел, а описание диапазона. Python не создаёт миллион элементов, чтобы выдать вам числа от нуля до миллиона. Диапазон хранит всего три вещи: с чего начинать, где заканчивать и с каким шагом. Числа рождаются в момент, когда цикл просит следующий.
big = range(1000000)
print(big)
print(len(list(range(1000000))))
range(0, 1000000) 1000000
Первая строка показывает, что range(1000000) — это диапазон, а не список: в скобках видны границы, а не миллион чисел. Вторая строка отвечает на практический вопрос «а сколько там шагов» — миллион. Но чтобы их увидеть, пришлось превратить диапазон в список, и вот тут память уже тратится по-настоящему.
range(начало, конец)
Два аргумента задают, с какого числа начать и каким закончить: range(начало, конец). Левая граница входит в перебор, правая — нет:
for day in range(1, 11):
print(f'День {day}')
День 1 День 2 День 3 День 4 День 5 День 6 День 7 День 8 День 9 День 10
Чтобы получить «от 1 до 10», правую границу пишут на единицу больше — 11. Это то же правило, что у срезов строк: s[1:11] тоже берёт символы с 1-го по 10-й — правило «левая включена, правая нет» в Python одно на всё. Промежуток без начала тоже валиден: range(5, 10) — числа 5, 6, 7, 8, 9. А запись range(5, 1) с началом больше конца даст пустой набор — цикл не сделает ни одного шага, разберём ниже.
| Запись | Числа | Сколько шагов |
|---|---|---|
| range(5) | 0, 1, 2, 3, 4 | 5 |
| range(1, 6) | 1, 2, 3, 4, 5 | 5 |
| range(2, 8) | 2, 3, 4, 5, 6, 7 | 6 |
| range(5, 1) | ничего | 0 |
Третий аргумент: шаг
Третий аргумент говорит, на сколько прыгать между числами. range(2, 11, 2) идёт от 2 до 10 с шагом 2 — только чётные:
for num in range(2, 11, 2):
print(num)
2 4 6 8 10
Шаг делает перебор экономным: не «все числа подряд», а каждое второе, каждое пятое. Последний прыжок может перескочить правую границу — тогда она просто не попадёт в перебор: range(1, 10, 3) даст 1, 4, 7 — а попытка прыгнуть с 7 на 10 уже не сработает, потому что 10 не входит.
Сколько шагов в диапазоне
Частый вопрос новичка: «а сколько раз выполнится тело?» Ответ считается на пальцах, но лучше один раз проверить руками. Длина диапазона — это просто разница границ, делённая на шаг: у range(1, 11) шагов десять, у range(2, 11, 2) — пять, у обратного range(10, 0, -1) — тоже десять.
print(len(range(5)))
print(len(range(1, 11)))
print(len(range(2, 11, 2)))
print(len(range(10, 0, -1)))
5 10 5 10
Функция len работает с диапазоном и не создаёт его в память: она просто считает шаги по правилам. Если вам нужно знать размер заранее — например, чтобы проверить, не обрежется ли что-то в конце, — считайте через len, а не гадайте.
Шаг не обязан попадать на границу
Границы диапазона и шаг не обязаны дружить. Если шаг не попадает ровно на правую границу, последний прыжок перескакивает её — и просто не попадает в перебор. Ничего не ломается, но стоит знать, что происходит:
for n in range(0, 10, 3):
print(n)
0 3 6 9
Дальше был бы прыжок с 9 на 12 — и 12 уже за правой границей, поэтому в перебор не попал. Отсюда практическое правило: если нужно «каждый третий до десяти включительно», границу пишут на единицу больше нужного: range(0, 11, 3) даст 0, 3, 6, 9 — а вот 12 не входит, потому что граница 11.
Обратный отсчёт
Отрицательный шаг переворачивает перебор: числа идут вниз, от начала к концу. Классика жанра — запуск ракеты:
for sec in range(3, 0, -1):
print(f'{sec}...')
print('Пуск!')
3... 2... 1... Пуск!
range(3, 0, -1) даёт 3, 2, 1 — и останавливается, не дойдя до нуля: правая граница не включается и при отрицательном шаге тоже. Если в отсчёте нужен сам ноль, границу пишут на единицу «ниже»: range(3, -1, -1) даст 3, 2, 1, 0:
for n in range(3, -1, -1):
print(n)
3 2 1 0
for n in range(5, 1):
print(n)
print('Тело не выполнилось ни разу')
Тело не выполнилось ни разу
for n in range(1, 10, 0):
print(n)
Диапазон нельзя изменить
Список можно пополнить методом append, а диапазон — нет. Это не недоработка, а сознательное решение: range описывает правило, а правило нельзя дополнить. Если во время цикла понадобится положить в него ещё одно число, придётся сначала превратить диапазон в список — и тогда про экономию памяти можно забыть.
r = range(5)
r.append(10)
Практика: рабочая неделя
Соберём вместе всё, что разобрали: диапазон дней, условие внутри тела, две ветки. Задача простая — отметить будни и выходные. Читается как готовая формула: диапазон даёт дни, условие делит их на две группы.
for day in range(1, 8):
if day % 2 == 0:
print(day, '- рабочий день')
else:
print(day, '- выходной')
1 - выходной 2 - рабочий день 3 - выходной 4 - рабочий день 5 - выходной 6 - рабочий день 7 - выходной
Остаток от деления % — рабочая лошадка в задачах с чётностью, и внутри цикла он работает ровно так же, как вне его. Обратите внимание на границу: диапазон задан как range(1, 8), поэтому дни идут с первого по седьмой — седьмой день уже входит, а вот range(1, 7) закончил бы перебор на шестом.
Когда range, а когда список
Правило выбора сводится к вопросу «что перебираем». Есть данные, которые нужно обработать, — цикл ходит по самим данным: по списку гостей, по строке, по словарю. Данных нет, а нужны повторы или номера, — берётся range: пять повторов, страницы от 1 до 10, обратный отсчёт. Соединять обе стороны умеет enumerate: он отдаёт и номер, и элемент сразу — урок 4 разбирает его целиком. А если совсем без данных, но с текстом на каждый шаг — диапазон печатает счёт прямо в теле, как в примерах выше.
range(n)— повторить действие n раз: нумерация с нуля, n шагов;range(начало, конец)— перебор по отрезку: левая граница входит, правая нет — как и у срезов;range(начало, конец, шаг)— прыжки через несколько: чётные, каждое пятое;- отрицательный шаг — обратный отсчёт:
range(10, 0, -1)идёт от 10 до 1.
range закрывает вопрос «сколько шагов». Но данные, по которым ходит for, — не только списки и диапазоны. Строка тоже последовательность, словарь перебирается по ключам, а файл — по строкам. Следующий урок расширит понятие «по чему можно идти циклом».
Сначала предскажи ответ в голове — это главный навык программиста.
for i in range(3):
print(i)
for n in range(3, 6):
print(n)
for n in range(6, 0, -2):
print(n)
1. Какие числа перебирает range(4)?
2. Сколько шагов сделает цикл for i in range(2, 8)?
3. Что делает третий аргумент range(0, 21, 5)?
4. Как написать обратный отсчёт от 5 до 1?
5. Что произойдёт с циклом for n in range(7, 3)?
6. Что напечатает range(1, 11) на последнем шаге?
7. Что произойдёт, если попытаться дописать в range(5) число 10?
8. Сколько чисел даст range(0, 10, 3)?
9. Чем range отличается от списка чисел?
Сделай обратный отсчёт от 5 до 1: печатай каждое число на своей строке, а после цикла — строку «Старт!».
Что делает range в Python?
range даёт последовательность чисел для перебора: range(5) — пять чисел от 0 до 4. Он не список, а «ленивый» счётчик, но в цикле for ведёт себя как список чисел: for i in range(5): print(i) напечатает числа от 0 до 4.
Урок 1: первый цикл forКак перебрать числа от 1 до 10?
range(1, 11): левая граница входит в перебор, правая нет, поэтому конец пишут на единицу больше нужного числа. Тот же принцип у срезов строк — правило «левая включена, правая нет» в Python единое.
Почему range(5) не доходит до 5?
Потому что range(n) обещает ровно n шагов: числа 0, 1, 2, 3, 4 — их пять. Нумерация в Python начинается с нуля, и правая граница всегда не включается. Если нужно включить n, пишут range(1, n + 1) или range(n + 1).
Как сделать обратный отсчёт в цикле?
Отрицательный шаг: range(10, 0, -1) перебирает числа 10, 9, ..., 1. Ноль в этот перебор не попадает; если нужен ноль на конце, границу опускают до -1: range(10, -1, -1).
Можно ли изменить range во время цикла?
Нет: диапазон неизменяем, и методов append или insert у него нет — Python ответит AttributeError. Если результаты нужно копить, заводите отдельный список и складывайте туда, а range оставьте генератором шагов.
Почему range(1, 11) даёт десять чисел, а не одиннадцать?
Правая граница не включается: перебор идёт по числам 1, 2, ..., 10 и останавливается перед 11. Чтобы последним было число N, границу пишут N + 1 — range(1, N + 1).
Понравился урок? Сошлитесь на него
«range(n) делает ровно n шагов: числа идут от 0 до n-1, а само число n не входит.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что дальше
Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.
Что читать дальше
Циклы · Урок 1
Цикл for в Python: первый цикл
Первый цикл for: компьютер повторяет одну строку за вас. Перебираем список, разбираем переменную цикла и тело с отступами — и видим, зачем цикл вместо копипасты.
Циклы · Урок 4
enumerate в Python: индекс и значение вместе
Нужен номер элемента вместе с самим элементом? enumerate отдаёт циклу пары «индекс — значение»: без ручного счётчика и с нумерацией с единицы через start=1.
Строки · Урок 2
Срезы в Python: s[start:stop:step]
Срез — способ вырезать из строки кусок: первые пять символов, последние три, каждый второй, строка наоборот. Разбираем s[start:stop:step] до автоматизма: индексы, границы, шаг.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
Flask · Урок 3
Шаблоны Jinja2: HTML-страницы с данными из Python
Третий урок курса Flask: шаблоны Jinja2 — переменные, циклы, фильтры и наследование base.html. Отличие этого урока: все примеры Jinja2 можно отрендерить прямо на странице.
jinja2 цикл for
aiogram · Урок 7
Асинхронность в aiogram: asyncio для бота без страха
Разбираем на живом коде, зачем aiogram асинхронный: async и await, asyncio.sleep против time.sleep и gather для параллельных чатов.
цикл событий asyncio
Циклы · Урок 14
Ошибки в циклах Python: от отступа до зависания
Ошибка в цикле повторяется на каждой итерации. Три полки цикловых ошибок — падение, молчаливая логика, зависание — и быстрый способ найти каждую.
indentationerror python циклбесконечный цикл while python ошибка