range() возвращает кортеж, который также как и список можно перебрать
range(2, 10) # (2, 3, 4, 5, 6, 7, 8, 9)
Ну строго говоря нет ... рэньж возвращает рэньж ;) более того он поддерживает слайсинг без итерирования и get_iterm (обращение по индексу) тоже без итерирования. Очень прикольная штука ;)
r = range(0,100000000000000000000000000000,2)
print(r)
r = r[::-13]
print(r)
r = r[:-100:7]
print(r)
print(r[100000000000000000000000000])
print(r[-100000000000000000000000000])
все это будет сделанно за O(1) с минимальными затратами памяти ;).
В принципе написать такой класс можно легко самому и я бы сказал что это неплохая тренировка, но некоторые скажу уууу математика ;)