← Назад к вопросам

Что происходит, если итератор достигает конца?

2.0 Middle🔥 61 комментариев
#Python Core#Soft Skills#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что происходит, когда итератор достигает конца

Когда итератор в Python достигает конца (исчерпывает все элементы), он генерирует исключение StopIteration. Это встроенное исключение сигнализирует о том, что больше элементов нет, и итерация должна завершиться.

Механизм работы итераторов

Любой итератор в Python реализует два метода:

class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):
        """Возвращает сам объект итератора"""
        return self
    
    def __next__(self):
        """Возвращает следующий элемент или вызывает StopIteration"""
        if self.index >= len(self.data):
            raise StopIteration  # Конец итерации!
        value = self.data[self.index]
        self.index += 1
        return value

# Использование
iterator = MyIterator([1, 2, 3])
print(next(iterator))  # 1
print(next(iterator))  # 2
print(next(iterator))  # 3
print(next(iterator))  # StopIteration!

Когда вызывается next() на итератор, который исчерпан, происходит следующее:

Исключение StopIteration

# Явный способ
data = [1, 2, 3]
it = iter(data)

print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
print(next(it))  # Вызовет StopIteration исключение
# Traceback (most recent call last):
#   File "script.py", line 7, in <module>
#     print(next(it))
# StopIteration

Это исключение не ошибка - это нормальное поведение, и Python использует его для остановки циклов.

Обработка в цикле for

Структура for автоматически перехватывает StopIteration и завершает цикл без ошибок:

# Это работает без исключений
for num in [1, 2, 3]:
    print(num)

# Происходит следующее "под капотом":
iterator = iter([1, 2, 3])
while True:
    try:
        num = next(iterator)
        print(num)
    except StopIteration:
        break  # Нормальное завершение

Обработка при явном использовании next()

Если вызываешь next() явно, нужно либо ловить исключение, либо передать значение по умолчанию:

data = [1, 2]
it = iter(data)

print(next(it))  # 1
print(next(it))  # 2

# Способ 1: ловим исключение
try:
    print(next(it))  # StopIteration
except StopIteration:
    print("Итератор исчерпан")

# Способ 2: используем default значение
it = iter(data)
print(next(it, "нет больше элементов"))  # нет больше элементов

Повторное использование итератора

Важное свойство: итератор нельзя перезапустить. Как только он исчерпан, next() всегда вызывает StopIteration:

data = [1, 2, 3]
it = iter(data)

# Итерируем до конца
for x in it:
    pass

# Пытаемся использовать ещё раз
print(next(it))  # StopIteration - итератор мертв

# Нужно создать новый итератор
it = iter(data)  # Новый итератор
print(next(it))  # 1 - теперь работает

Если нужна возможность повторного использования, создай новый итератор:

class ResettableIterator:
    def __init__(self, data):
        self.data = data
    
    def __iter__(self):
        self.index = 0
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        value = self.data[self.index]
        self.index += 1
        return value

it = ResettableIterator([1, 2, 3])
print(list(it))  # [1, 2, 3]
print(list(it))  # [1, 2, 3] - работает, потому что __iter__ сбросит index

Сравнение: итератор vs итерируемый объект

# Итерируемый объект (имеет __iter__)
data = [1, 2, 3]  # list - итерируемый
for x in data:
    pass
for x in data:  # Можно повторять!
    pass

# Итератор (имеет __iter__ и __next__)
it = iter(data)  # iterator - итератор
for x in it:
    pass
for x in it:  # Будет пусто! Итератор исчерпан
    pass

Практический пример: создание бесконечного итератора

class InfiniteCounter:
    """Итератор, который никогда не заканчивается"""
    def __init__(self, start=0):
        self.current = start
    
    def __iter__(self):
        return self
    
    def __next__(self):
        value = self.current
        self.current += 1
        return value

# Использование
counter = InfiniteCounter(10)
for i in range(5):
    print(next(counter))  # 10, 11, 12, 13, 14
# Никогда не вызовет StopIteration (если не остановим цикл)

Итоги

  1. StopIteration - исключение, сигнализирующее об исчерпании итератора
  2. Цикл for автоматически перехватывает это исключение
  3. next() с явным вызовом требует обработки или default параметра
  4. Итератор нельзя перезапустить - он одноразовый
  5. Итерируемый объект может создавать новые итераторы через __iter__
Что происходит, если итератор достигает конца? | PrepBro