Числовые диапазоны в 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.