Инструмент для порождения чисел
range() делает ровно одну вещь - производит последовательность целых чисел. Это главный напарник for-циклов, когда нужно проитерироваться заданное число раз или пройтись по числовому интервалу.
Самая простая форма принимает один аргумент - stop:
Вывод:
0
1
2
3
4
Две детали, которые ловят новичков:
- Счёт начинается с 0.
range(5)даёт пять чисел, начиная с 0. - Значение stop исключается.
range(5)останавливается перед 5 - само 5 не входит.
Эти правила согласуются по всему Python - в срезах, индексации и range. Как только усвоишь «stop не входит», спотыкаться перестанешь.
Три формы
range() принимает один, два или три аргумента:
Step - это размер каждого скачка. range(0, 20, 4) выдаёт каждое четвёртое число. Держи это в голове в следующий раз, когда нужно «каждый второй элемент» или «каждый десятый сэмпл».
Счёт в обратную сторону
Шаг может быть отрицательным, и тогда ты считаешь назад:
Опять же, stop исключается - range(10, 0, -1) останавливается перед 0, а не на 0. Чтобы включить 0, поставь stop равным -1:
range ленив
В Python 3 range() не строит список чисел в памяти. Он возвращает лёгкий range-объект, который производит числа по одному по требованию. Поэтому ты можешь писать:
Миллиард-числовой «range» занимает фактически ноль памяти. Числа генерируются тогда, когда цикл их просит.
Если список чисел действительно нужен - чтобы модифицировать, отсортировать или индексировать за пределами базового - конвертируй явно:
Чаще всего список не нужен. for i in range(...) работает напрямую.
Типичные паттерны
Горстка рецептов, которые ты будешь использовать постоянно:
Сделать что-то n раз.
_ - соглашение со значением «это значение мне не интересно»: Python его не навязывает, но любой читатель поймёт намерение.
Индексировать по последовательности.
Предпочитай enumerate() вместо range(len(...)), но если нужен именно индекс:
Всё равно в большинстве случаев enumerate(items) чище.
Проходить через каждый второй элемент.
Выведет a, c, e. Для простого прореживания, впрочем, синтаксис срезов ещё прямее: items[::2].
Быстро получить числовой список.
Это списковое включение - о нём позже, - но числа поставляет range.
Чем range() не является
Два острых края, которые стоит знать:
rangeпроизводит только целые. Если нужен вещественный шаг (например, от 0.0 до 1.0 с шагом 0.1) - используйnumpy.arangeили цикл со своим счётчиком.rangeне работает с произвольными итерируемыми. Он строго для целых чисел. Если ты пытаешься «range-нуть» по списку - тебе нуженenumerateили просто сам список.
Собираем вместе
Небольшой пример, использующий несколько вариаций разом:
Два вложенных цикла на range, дающие сетку. Заметь, что оба цикла стартуют с 1 - range(1, 6), - потому что мы хотим метки от 1 до 5.
Переходим к коллекциям
Ты уже видел условия, оба типа циклов и range. Этого достаточно, чтобы управлять любой коллекцией. Следующая глава - сами коллекции: списки, кортежи, множества и словари.
Часто задаваемые вопросы
Что делает range() в Python?
range() производит последовательность целых чисел. range(n) даёт числа от 0 до n-1. range(start, stop) - целые от start до, но не включая stop. range(start, stop, step) позволяет выбрать шаг, включая отрицательный для счёта в обратную сторону.
range() создаёт список?
range() создаёт список?Нет. В Python 3 range() возвращает лёгкий range-объект, генерирующий числа по требованию. Поэтому range(10**9) мгновенен - он не выделяет миллиард целых. Оберни в list(...), если список действительно нужен.
Как считать в обратную сторону с range()?
Используй отрицательный шаг: range(10, 0, -1) даёт 10, 9, 8, ..., 1. Помни, что stop всегда исключается, так что чтобы включить 0, пиши range(10, -1, -1).