Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Является ли range итератором?
Короткий ответ: НЕТ. range — это итерируемый объект, а не итератор.
Разница
# range — ИТЕРИРУЕМЫЙ объект (есть __iter__)
r = range(5)
print(hasattr(r, '__iter__')) # True
print(hasattr(r, '__next__')) # False — нет этого метода!
# Это значит: range можно использовать в for цикле,
# но это не итератор
Как это работает
# range — итерируемый
r = range(3)
# Для итерации нужно создать итератор
iterator = iter(r) # Создаём итератор из range
print(type(iterator)) # <class 'range_iterator'>
# Теперь можем использовать next()
print(next(iterator)) # 0
print(next(iterator)) # 1
print(next(iterator)) # 2
# print(next(iterator)) # StopIteration
Под капотом for цикла
# Когда пишешь
for i in range(3):
print(i)
# Python делает
iterator = iter(range(3)) # Создаёт итератор
while True:
try:
i = next(iterator)
print(i)
except StopIteration:
break
Проверка методов
r = range(5)
# Есть __iter__
print(r.__iter__) # <method-wrapper '__iter__' of range object>
# НЕТ __next__
print(r.__next__) # AttributeError: 'range' object has no attribute '__next__'
# Сравни с итератором
it = iter(r)
print(it.__iter__) # <method-wrapper '__iter__' of range_iterator object>
print(it.__next__) # <method-wrapper '__next__' of range_iterator object>
Почему это важно
1. range можно итерировать много раз
r = range(3)
# Первый раз
for i in r:
print(i) # 0, 1, 2
# Второй раз (работает!)
for i in r:
print(i) # 0, 1, 2 (снова)
2. Итератор исчерпывается после использования
it = iter(range(3))
# Первая итерация
for i in it:
print(i) # 0, 1, 2
# Вторая попытка
for i in it:
print(i) # Ничего не выведет (итератор исчерпан)
Другие примеры
# ИТЕРИРУЕМЫЕ (но не итераторы)
list([1, 2, 3]) # есть __iter__, нет __next__
str("hello") # есть __iter__, нет __next__
dict({"a": 1}) # есть __iter__, нет __next__
set([1, 2, 3]) # есть __iter__, нет __next__
range(10) # есть __iter__, нет __next__
# ИТЕРАТОРЫ (имеют оба метода)
iter([1, 2, 3]) # есть __iter__ и __next__
iter("hello") # есть __iter__ и __next__
iter({"a": 1}) # есть __iter__ и __next__
open("file.txt") # есть __iter__ и __next__
(x for x in range(3)) # генератор — есть оба
Оптимизация в Python 3
# range очень эффективен — не хранит все числа в памяти
r = range(1000000)
print(r) # range(0, 1000000) — просто объект, без памяти на числа
# Списки, наоборот, хранят всё
l = list(range(1000000))
print(l) # [0, 1, 2, ...] — использует 40+ МБ памяти
Это одна из причин, почему range лучше использовать, чем list(range(...)) в цикле.
Быстрая проверка
# Функция для проверки типа объекта
def check_type(obj):
is_iterable = hasattr(obj, '__iter__')
is_iterator = hasattr(obj, '__next__')
if is_iterator:
return "Это ИТЕРАТОР"
elif is_iterable:
return "Это ИТЕРИРУЕМЫЙ (но не итератор)"
else:
return "Это не итерируемый и не итератор"
print(check_type(range(5))) # Это ИТЕРИРУЕМЫЙ (но не итератор)
print(check_type(iter(range(5)))) # Это ИТЕРАТОР
print(check_type([1, 2, 3])) # Это ИТЕРИРУЕМЫЙ (но не итератор)
print(check_type(iter([1, 2]))) # Это ИТЕРАТОР
print(check_type(42)) # Это не итерируемый и не итератор
Вывод
✅ range — ИТЕРИРУЕМЫЙ объект
✅ range — НЕ ИТЕРАТОР
✅ iter(range(...)) — ИТЕРАТОР
✅ range можно итерировать несколько раз
✅ range очень экономный (не хранит значения в памяти)
Это одна из самых частых ошибок на собеседованиях — путаница между итерируемыми объектами и итераторами.