В чём причина почти постоянного размера объекта range при огромном числе его элементов?
Объект range хранит не сами элементы, а компактное описание последовательности: начальное значение, конечную границу и шаг. Поэтому размер объекта почти не зависит от количества чисел в диапазоне: элементы вычисляются по мере обращения к ним.
Это экономит память, но не делает любую операцию над диапазоном бесплатной: последовательный обход всё равно требует времени, а преобразование в список материализует все элементы.
Такой подход появился для представления числовых последовательностей без обязательного создания большого контейнера в памяти. Хранение всех значений особенно невыгодно для регулярных диапазонов, где каждый следующий элемент можно получить арифметически.
В Python диапазон является отдельным неизменяемым объектом-последовательностью, а не сокращённой формой уже созданного списка. Это позволяет использовать его как источник итерации с небольшим фиксированным объёмом служебных данных.
Создание списка из миллионов чисел требует памяти под контейнер и ссылки на элементы, а сами целые числа являются объектами Python. Для больших диапазонов это может привести к высокому пиковому потреблению памяти и дополнительным затратам на создание объектов.
Ошибка возникает, когда разработчик считает, что любой перебор диапазона бесплатен по памяти. Сам range компактен, но операция его материализации, например передача в функцию, ожидающую список, устраняет это преимущество.
Внутри range сохраняются параметры, достаточные для описания последовательности: начало, конец и шаг. Логически элемент с индексом i определяется как начало плюс i, умноженное на шаг, если индекс находится в допустимых границах.
При итерации значения выдаются последовательно, поэтому весь диапазон не хранится одновременно. В каждый момент времени вызывающий код обычно работает только с текущим значением, хотя конкретные временные объекты и их жизненный цикл зависят от реализации и контекста использования.
Компактность не означает, что диапазон ограничен небольшими числами: его границы представлены объектами целого типа произвольной точности. Однако очень большие числа сами могут занимать больше памяти, поэтому постоянный размер относится к фиксированному числу параметров, а не к абсолютному числу байтов при любых значениях.
Проверка принадлежности числу диапазону может выполняться без полного перебора: проверяется соответствие границам и шагу. Это отличается от преобразования диапазона в список, которое создаёт все элементы и требует памяти, пропорциональной их количеству.
В задаче нужно выполнить обработку для всех идентификаторов от нуля до нескольких десятков миллионов. Вариант со списком прост для передачи между функциями, но заранее создаёт крупную структуру и увеличивает пиковое потребление памяти.
Вариант с range передаёт компактное описание последовательности и подходит, если обработка выполняется последовательно. Если же данные нужно многократно перемешивать, индексировать произвольно с сохранением всех значений или передавать компоненту, требующей материальный список, список может быть оправдан, но его создание следует учитывать в бюджете памяти.
Выбранным решением будет range для последовательного обхода. Он не создаёт все значения заранее, снижает память до постоянной относительно размера диапазона величины и сохраняет линейное время полного обхода. Результат — отсутствие ненужной материализации миллионов элементов; компромисс состоит в том, что повторные проходы снова вычисляют значения.
Освобождает ли range память после частичного обхода?
Сам объект range изначально не владеет массивом всех элементов, поэтому после частичного обхода ему нечего освобождать в этом смысле. Память текущих временных значений определяется кодом, который их получает и сохраняет. Если обработанные значения складываются в список, память будет расти уже из-за этого списка.
Почему преобразование range в список меняет характеристики памяти?
Преобразование в список требует создать контейнер со всеми элементами диапазона. Поэтому память становится зависящей от количества элементов, а не только от трёх параметров диапазона. Если элементы сохраняются как обычные Python-целые, учитываются и ссылки в списке, и объекты чисел, за исключением случаев, когда конкретные значения переиспользуются реализацией.
Можно ли считать range полноценной заменой списку?
Нет. range эффективен для регулярной последовательности с фиксированными началом, концом и шагом, но не хранит произвольные заранее вычисленные значения. Он не поддерживает операции, требующие изменяемого контейнера, и не подходит, если нужен случайный порядок, частое изменение элементов или сохранение результатов дорогостоящего вычисления.