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

Что происходит при окончании перебора последовательности в итераторе Python?

3.0 Senior🔥 241 комментариев
#DevOps и инфраструктура#Django

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

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

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

Окончание перебора в итераторе Python

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

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

Каждый итератор в Python должен реализовать два метода:

class CustomIterator:
    def __iter__(self):
        """Возвращает сам итератор"""
        return self
    
    def __next__(self):
        """Возвращает следующий элемент или выбрасывает StopIteration"""
        if self.has_next():
            return self.get_next_value()
        else:
            raise StopIteration  # Это конец итерации!

Практический пример

class CountUp:
    def __init__(self, max_value):
        self.max = max_value
        self.current = 1
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current <= self.max:
            value = self.current
            self.current += 1
            return value
        else:
            raise StopIteration

counter = CountUp(3)
print(next(counter))  # 1
print(next(counter))  # 2
print(next(counter))  # 3
print(next(counter))  # StopIteration!

Как цикл for обрабатывает StopIteration

Цикл for автоматически перехватывает это исключение:

for num in CountUp(3):
    print(num)

# Что на самом деле происходит:
iterator = CountUp(3).__iter__()
while True:
    try:
        num = iterator.__next__()
        print(num)
    except StopIteration:
        break  # Цикл автоматически заканчивается

Явное использование next()

Если вызывать next() вручную после конца последовательности:

data = iter([1, 2, 3])
print(next(data))  # 1
print(next(data))  # 2
print(next(data))  # 3
print(next(data))  # StopIteration exception

Можно предоставить значение по умолчанию:

data = iter([1, 2, 3])
print(next(data, "No more"))  # 1
print(next(data, "No more"))  # 2
print(next(data, "No more"))  # 3
print(next(data, "No more"))  # No more вместо исключения

Встроенные итераторы Python

Все встроенные типы следуют этому протоколу:

it = iter([1, 2, 3])
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
print(next(it))  # StopIteration

it = iter("ABC")
print(next(it))  # A
print(next(it))  # B
print(next(it))  # C
print(next(it))  # StopIteration

Генераторы и StopIteration

Генераторы тоже выбрасывают StopIteration, но это происходит автоматически:

def simple_generator():
    yield 1
    yield 2
    yield 3

gen = simple_generator()
print(next(gen))  # 1
print(next(gen))  # 2
print(next(gen))  # 3
print(next(gen))  # StopIteration

Обработка StopIteration

Обычно не ловите вручную, но иногда нужно:

def get_first_element(iterable, default=None):
    try:
        return next(iter(iterable))
    except StopIteration:
        return default

print(get_first_element([1, 2, 3]))  # 1
print(get_first_element([], default=42))  # 42

PEP 479: Изменения в Python 3.7+

Если внутри генератора выбросить StopIteration, она автоматически преобразуется в RuntimeError:

def bad_generator():
    yield 1
    raise StopIteration  # В Python 3.7+ это RuntimeError!

def good_generator():
    yield 1
    return  # Правильно

Ключевые моменты

  1. StopIteration — это нормальный сигнал завершения
  2. Цикл for автоматически его перехватывает
  3. next() с параметром безопаснее вручную
  4. Кастомные итераторы должны его выбрасывать
  5. Генераторы выбрасывают его автоматически

Это фундаментальная часть Python протокола итерирования.