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

Почему не срабатывает StopIteration при использовании for в Python?

2.2 Middle🔥 151 комментариев
#Другое

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

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

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

Почему не срабатывает StopIteration при использовании for в Python?

Правильный ответ: StopIteration срабатывает, но её автоматически перехватывает цикл for. Это не ошибка, а именно так устроена работа итераторов в Python.

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

Цикл for — это синтаксический сахар для работы с итераторами. Вот что происходит под капотом:

# Это что ты пишешь
for item in iterable:
    print(item)

# Вот что Python делает на самом деле
iterator = iter(iterable)  # Получаем итератор

try:
    while True:
        item = next(iterator)  # Получаем следующий элемент
        print(item)            # Используем его
except StopIteration:        # Когда StopIteration вызвана
    pass                       # Просто выходим из цикла

Цикл for перехватывает исключение StopIteration и останавливается. Ты этого не видишь, потому что это встроенное поведение.

Пример с явным использованием next()

Если использовать next() вручную, StopIteration будет видна:

lst = [1, 2, 3]
iterator = iter(lst)

print(next(iterator))  # 1
print(next(iterator))  # 2
print(next(iterator))  # 3
print(next(iterator))  # StopIteration ошибка!

Алилэкс может видеть исключение, если не обработать его:

lst = [1, 2, 3]
iterator = iter(lst)

try:
    while True:
        print(next(iterator))
except StopIteration:
    print("Итератор закончился")

# Вывод:
# 1
# 2
# 3
# Итератор закончился

Создание собственного итератора

Когда создаёшь свой итератор, нужно выбросить StopIteration когда элементов больше нет:

class CountUp:
    def __init__(self, max):
        self.max = max
        self.current = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.current < self.max:
            self.current += 1
            return self.current
        else:
            raise StopIteration  # Явно выбрасываем исключение

# Цикл for перехватит StopIteration
for num in CountUp(3):
    print(num)

# Вывод:
# 1
# 2
# 3

Цикл for автоматически обработал StopIteration.

Генератор (более простой способ)

Генераторы автоматически вызывают StopIteration:

def count_up(max):
    current = 0
    while current < max:
        current += 1
        yield current  # Возвращает значение и паузирует функцию
    # После последнего yield функция заканчивается
    # и автоматически вызывается StopIteration

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

# Вывод:
# 1
# 2
# 3

Почему это сделано так?

1. Удобство — не нужно писать try/except в цикле

# ❌ Неудобно
iterator = iter([1, 2, 3])
try:
    while True:
        print(next(iterator))
except StopIteration:
    pass

# ✅ Удобно
for item in [1, 2, 3]:
    print(item)

2. Стандарт — все итерируемые объекты работают одинаково

3. Абстракция — пользователь не должен знать, как устроена работа итератора

Важное правило Python 3.7+

В Python 3.7 был изменён стандарт: если в генераторе возвращается значение (return value), оно становится значением StopIteration:

def generator_with_return():
    yield 1
    yield 2
    return "Finished"  # Значение передаётся в StopIteration

# Цикл for всё ещё игнорирует это значение
for num in generator_with_return():
    print(num)  # 1, 2

# Но если использовать next() явно:
try:
    gen = generator_with_return()
    while True:
        print(next(gen))
except StopIteration as e:
    print(f"Возвращённое значение: {e.value}")  # Finished

Сравнение разных способов итерации

lst = [10, 20, 30]

# 1. Цикл for (самый простой)
for item in lst:
    print(item)

# 2. Цикл while с next() (видна StopIteration)
iterator = iter(lst)
while True:
    try:
        item = next(iterator)
        print(item)
    except StopIteration:
        break

# 3. Цикл while с next() и дефолтным значением
iterator = iter(lst)
while (item := next(iterator, None)) is not None:
    print(item)

Заключение

  • StopIteration не срабатывает, потому что её перехватывает цикл for
  • Это нормальное поведение, а не баг
  • Для обычной итерации используй for — не нужно беспокоиться о StopIteration
  • Если работаешь с next() вручную, то StopIteration будет видна
  • Генераторы автоматически вызывают StopIteration в конце
  • Этот механизм позволяет создавать чистый и понятный код
Почему не срабатывает StopIteration при использовании for в Python? | PrepBro