Числовые диапазоны в Python: от простого к практическому применению

Раздел: Алгоритмы -> Диапазоны

Основные возможности функции range

Функция range в Python создает неизменяемую последовательность целых чисел. Она часто используется для итерации в циклах for и для генерации списков чисел. range имеет три формы вызова: range(stop), range(start, stop) и range(start, stop, step). Результатом является объект типа range, который экономит память, так как не хранит все элементы сразу.

Наиболее эффективный способ создания диапазона чисел - использование встроенной функции range.

# range с одним аргументом: числа от 0 до 9
r = range(10)
print(list(r))  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# range с двумя аргументами: от 5 до 10 (не включая 10)
r2 = range(5, 10)
print(list(r2)) # [5, 6, 7, 8, 9]

# range с тремя аргументами: от 2 до 20 с шагом 3
r3 = range(2, 20, 3)
print(list(r3)) # [2, 5, 8, 11, 14, 17]

Python промежуток чисел (работа с диапазоном чисел (range) в python)

Возможные проблемы и ошибки:

  • Шаг равен нулю: ValueError: range() arg 3 must not be zero. Пример: range(0, 10, 0).
  • Нецелые аргументы: TypeError: 'float' object cannot be interpreted as an integer. range принимает только целые числа.
  • Забывание, что stop не включается: часто ошибочно полагают, что range(1, 5) выдаст 1,2,3,4,5, но на самом деле 5 не входит.
  • Пустой диапазон: если start >= stop при положительном шаге (или наоборот при отрицательном), range пуст.

Как создать список чисел из объекта range?

Чтобы получить обычный список с элементами диапазона, используют функцию list().

numbers = list(range(5, 15, 2))
print(numbers)  # [5, 7, 9, 11, 13]

Проблема: для очень больших диапазонов (например, range(10**8)) преобразование в список приводит к огромному потреблению памяти и может вызвать MemoryError. Решение: итерировать непосредственно по объекту range, не создавая список.

Как получить диапазон чисел с плавающей точкой?

Встроенный range не поддерживает дробные шаги. Альтернативы:

  • numpy.arange (требует установки библиотеки NumPy).
  • Самодельный генератор через цикл while или с использованием itertools.takewhile.
# Пример с циклом while
def float_range(start, stop, step):
    while start < stop:
        yield round(start, 10)
        start += step

for x in float_range(0.0, 1.0, 0.1):
    print(x, end=' ')  # 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9

Ошибки: Накопление погрешности при сложении дробных чисел. Рекомендуется использовать round или работать с целыми числами, а затем делить.

Как создать обратный диапазон (убывающий)?

Для убывающей последовательности используют отрицательный шаг.

# от 10 до 0 включительно с шагом -1
for i in range(10, -1, -1):
    print(i, end=' ')  # 10 9 8 7 6 5 4 3 2 1 0

Типичная ошибка: путаница с границами. range(10, 0, -1) выдаст 10,9,…,1 (0 не входит, потому что stop=0 не включается). Для включения 0 нужно stop=-1.

Как перебирать числа с шагом больше 1?

Третий аргумент step задает шаг. Например, получить чётные числа от 0 до 20.

evens = list(range(0, 21, 2))
print(evens)  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Как получить диапазон, включающий последнее число (inclusive range)?

Поскольку range не включает stop, можно увеличить stop на 1 или использовать библиотечную функцию, например numpy.linspace для равномерного распределения. Самый простой способ: написать range(start, stop+1).

# числа от 1 до 5 включительно
inclusive = list(range(1, 6))
print(inclusive)  # [1, 2, 3, 4, 5]

Осторожность: при отрицательном шаге нужно вычитать: range(5, 0-1, -1).

Расширенные примеры применения range

Использование range для индексации списка

Цикл по индексам с помощью range(len(list)) - классический приём, хотя часто предпочтительнее enumerate.

Пример
fruits = ['apple', 'banana', 'cherry']
for i in range(len(fruits)):
    print(f'{i}: {fruits[i]}')
0: apple
1: banana
2: cherry

Генерация списков с помощью включений (list comprehension) на основе range

Пример
# квадраты чисел от 0 до 9
squares = [x**2 for x in range(10)]
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

Итерация по двум последовательностям через zip и range

Пример
names = ['Alice', 'Bob', 'Charlie']
scores = [85, 92, 78]
for i in range(min(len(names), len(scores))):
    print(f'{names[i]}: {scores[i]}')
Alice: 85
Bob: 92
Charlie: 78

Создание собственного инклюзивного диапазона через класс

Пример
class InclusiveRange:
    def __init__(self, start, stop, step=1):
        self.start = start
        self.stop = stop
        self.step = step
    
    def __iter__(self):
        current = self.start
        while (self.step > 0 and current <= self.stop) or (self.step < 0 and current >= self.stop):
            yield current
            current += self.step

# пример
for x in InclusiveRange(1, 5):
    print(x, end=' ')  # 1 2 3 4 5

Работа с большими диапазонами без использования памяти

Объект range занимает постоянный объем памяти независимо от размера. Можно передавать его в функции, ожидающие итерируемый объект.

Пример
large_range = range(10**9)  # занимает ~48 байт
# безопасное суммирование без создания списка
total = sum(large_range)  # считает сумму 0..999999999
print(total)  # 499999999500000000

Использование range с itertools.islice для частичного обхода

Пример
from itertools import islice
# взять первые 5 элементов из большого диапазона
first_five = list(islice(range(1000), 5))
print(first_five)  # [0, 1, 2, 3, 4]

Создание последовательности дат с помощью range (перевод количества дней)

Пример
from datetime import datetime, timedelta
start_date = datetime(2024, 1, 1)
for i in range(5):
    day = start_date + timedelta(days=i)
    print(day.strftime('%Y-%m-%d'))
2024-01-01
2024-01-02
2024-01-03
2024-01-04
2024-01-05

Ошибка: передача float в range

Пример
try:
    r = range(0.5, 10)  # TypeError
except TypeError as e:
    print('Ошибка:', e)
Ошибка: 'float' object cannot be interpreted as an integer

Совет: для дробных шагов используйте numpy.arange

Пример
import numpy as np
arr = np.arange(0.0, 1.0, 0.1)
print(arr)  # [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]

Примечание: numpy.arange также может иметь проблемы с округлением при больших шагах, поэтому для равномерных интервалов предпочтительнее numpy.linspace.

Работа с диапазоном чисел (range) в Python - comments

En
Python промежуток чисел (python)