Основы Python: работа с числовыми диапазонами
Основы работы с диапазонами чисел
В Python для генерации последовательностей целых чисел применяется встроенная функция range(). Она является основой многих циклов и алгоритмов. Рассмотрим её возможности и различные способы использования.
Функция range(): базовый синтаксис
range(stop) создаёт числа от 0 до stop-1. range(start, stop) задаёт начало и конец (исключительно). range(start, stop, step) определяет шаг. Пример:
for i in range(5):
print(i, end=' ')
# Вывод: 0 1 2 3 4
for i in range(2, 8):
print(i, end=' ')
# Вывод: 2 3 4 5 6 7
for i in range(0, 10, 2):
print(i, end=' ')
# Вывод: 0 2 4 6 8диапазоны python (диапазоны чисел в python)
Пояснение: range генерирует числа лениво (итератор) и не хранит их все в памяти. Это эффективно для больших диапазонов.
Типичная ошибка: передача дробных чисел. range() принимает только целые аргументы. Решение: преобразовать значения в int или использовать другой подход, например генератор с while.
Как получить список чисел из диапазона?
Для создания списка используется list(range(...)). Цель: когда требуется изменяемый список для дальнейших модификаций.
nums = list(range(0, 10, 2))
print(nums) # [0, 2, 4, 6, 8]Примечание: при очень больших диапазонах (например, range(10**7)) такой список займёт много памяти. Лучше работать с итератором напрямую.
Проблема: MemoryError при попытке создать список из огромного range. Решение: не преобразовывать в список без необходимости, использовать range в цикле или срезы.
Как перебрать элементы списка по индексу?
Можно использовать for i in range(len(lst)), но современный стиль рекомендует enumerate().
lst = ['a', 'b', 'c']
for i in range(len(lst)):
print(i, lst[i])
# 0 a
# 1 b
# 2 c
for i, val in enumerate(lst):
print(i, val)Проблема: изменение списка внутри цикла for i in range(len(lst)) может привести к пропуску элементов. Решение: копировать список или обходить в обратном порядке.
Как создать убывающий диапазон?
Указать отрицательный шаг. Например, range(10, 0, -1) даст числа от 10 до 1 (исключая 0).
for i in range(10, 0, -1):
print(i, end=' ')
# 10 9 8 7 6 5 4 3 2 1Путаница с границами: чтобы включить 0, нужно range(10, -1, -1). Также легко забыть, что шаг должен быть отрицательным, иначе диапазон будет пустым.
Как проверить принадлежность числа диапазону без цикла?
Оператор in работает с range: if x in range(0, 100):. Это выполняется за O(1) благодаря математической проверке.
x = 50
if x in range(0, 100):
print('в диапазоне')
# в диапазонеДля очень больших чисел проверка остаётся быстрой, но сбивает с толку начинающих, которые ожидают прохода по всем элементам.
Как сгенерировать диапазон с плавающей точкой?
Встроенный range() не поддерживает float. Альтернативы: numpy.arange или собственный генератор.
# Генератор с while
def frange(start, stop, step):
while start < stop:
yield start
start += step
for x in frange(0.0, 1.0, 0.2):
print(x, end=' ')
# 0.0 0.2 0.4 0.6 0.8
# С использованием numpy
import numpy as np
print(np.arange(0.0, 1.0, 0.2))
# [0. 0.2 0.4 0.6 0.8]Проблема: numpy не входит в стандартную библиотеку. Для учебных целей подойдёт генератор, однако он накапливает ошибки округления.
Расширенные примеры использования range()
Отрицательные числа и шаг
Range работает и с отрицательными значениями. Пример: создание чисел от -10 до -1 с шагом 2.
for i in range(-10, -1, 2):
print(i, end=' ')
# -10 -8 -6 -4 -2Результат: -10 -8 -6 -4 -2
Если шаг положительный, а start больше stop, диапазон будет пустым.
Генератор списка на основе range
Range часто используется в list comprehensions для создания последовательностей.
squares = [x**2 for x in range(10)]
print(squares)
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]Range и reversed
Функция reversed() позволяет перебирать числа в обратном порядке без создания списка.
for i in reversed(range(5)):
print(i, end=' ')
# 4 3 2 1 0Результат: 4 3 2 1 0
Параллельный перебор с zip и range
Для одновременного обхода нескольких списков по индексам можно использовать zip(range(len(list1)), list1, list2).
list1 = ['a','b','c']
list2 = [1,2,3]
for idx, v1, v2 in zip(range(len(list1)), list1, list2):
print(idx, v1, v2)
# 0 a 1
# 1 b 2
# 2 c 3Создание двумерного списка (матрицы)
Range вложенных циклов упрощает создание матриц.
matrix = [[i+j for j in range(3)] for i in range(3)]
print(matrix)
# [[0, 1, 2], [1, 2, 3], [2, 3, 4]]Range с большим шагом и проверка in
Оператор in работает даже для огромных диапазонов.
big_range = range(0, 10**9, 1000)
print(500000 in big_range) # True (проверка за O(1))
print(500001 in big_range) # FalseTrue False
Срезы range (range slicing)
Range поддерживает срезы, возвращая новый range-объект. Это удобно для выделения поддиапазонов.
r = range(0, 10, 1)
sub = r[2:5] # range(2, 5)
print(list(sub)) # [2, 3, 4]
sub_step = r[1:8:3] # range(1, 8, 3)
print(list(sub_step)) # [1, 4, 7][2, 3, 4] [1, 4, 7]
Количество элементов в диапазоне
Функция len() возвращает число элементов без их генерации.
r = range(5, 100, 2)
print(len(r)) # 4848
Range с itertools.islice для частичного обхода
Пропустить первые N элементов большого диапазона.
from itertools import islice
big_range = range(10**6)
# Взять первые 10 элементов, начиная с 100
first_ten = list(islice(big_range, 100, 110))
print(first_ten) # [100, 101, 102, 103, 104, 105, 106, 107, 108, 109][100, 101, 102, 103, 104, 105, 106, 107, 108, 109]
Пустой диапазон и его проверка
Пустой диапазон возникает, когда start >= stop при положительном шаге или наоборот при отрицательном.
if not range(5, 5):
print('диапазон пуст')
# диапазон пуст
# Также можно проверить длину
print(len(range(10, 5))) # 0