Подтвердить что ты не робот

Почему в следующий раз возникает "StopIteration", но "for" делает нормальное возвращение?

В этом фрагменте кода, почему использование for приводит к отсутствию StopIteration или циклу for перехватывает все исключения и затем молча завершается? В каком случае, почему у нас есть посторонний return? Или raise StopIteration вызвано: return None?

#!/usr/bin/python3.1
def countdown(n):
    print("counting down")
    while n >= 9:
        yield n
        n -= 1
    return

for x in countdown(10):
    print(x)

c = countdown(10)
next(c)
next(c)
next(c)

Предполагая, что StopIteration вызывается: return None. Когда генерируется GeneratorExit?

def countdown(n):
    print("Counting down from %d" % n)
    try:
        while n > 0:
            yield n
            n = n - 1
    except GeneratorExit:
        print("Only made it to %d" % n)

Если я вручную сделаю:

c = countdown(10)
c.close() #generates GeneratorExit??

В каком случае, почему я не вижу следа?

4b9b3361

Ответ 1

Цикл for явно прослушивает StopIteration.

Цель оператора for состоит в том, чтобы перебрать последовательность, предоставленную итератором, и исключение используется, чтобы сигнализировать, что итератор теперь выполнен; for не обнаруживает других исключений, вызванных повторением итерации объекта, только этого.

Это потому, что StopIteration - это нормальный ожидаемый сигнал, чтобы сказать, кто из вас повторяет, что больше ничего не будет создано.

Функция генератора - это особый тип итератора; он действительно поднимает StopIteration, когда функция выполняется (т.е. когда она возвращается, поэтому да, return None повышает StopIteration). Это требование итераторов; они должны поднять StopIteration, когда они будут сделаны; на самом деле, как только a StopIteration был поднят, попытка получить из него еще один элемент (через next() или вызов метода .next() (py 2) или .__next__() (py 3) на итераторе) всегда снова поднимите StopIteration.

GeneratorExit является исключением для связи в другом направлении. Вы явно закрываете генератор с выражением yield, и способ, которым Python сообщает это замыкание генератору, - это повышение GeneratorExit внутри этой функции. Вы явно поймали это исключение внутри countdown, его цель - дать генератору очистить ресурсы по мере необходимости при закрытии.

A GeneratorExit не передается вызывающему; см. generator.close() документация.