попробуй наконец в генераторе Python 3 - PullRequest
4 голосов
/ 09 мая 2019

Я встретил фрагмент кода Python 3:

def gen():
    try:
        while True:
            yield 1
    finally:
        print("stop")

print(next(gen()))

После того, как я запустил его, я сначала подумал, что вывод должен быть:

1

Но на самом деле результат:

stop
1

Как это может произойти? Что случилось под капотом?

Если я запусту for i in gen(): print(i), будет бесконечный цикл, что я и ожидал. В чем разница между for и next здесь?

Ответы [ 2 ]

5 голосов
/ 09 мая 2019

Предложение finally выполняется при сборке мусора объекта генератора.

Рассмотрим следующие два сценария:

def gen():
    try:
        while True:
            yield 1
    finally:
        print("stop")

g1 = gen(); print('first time')
print(next(g1))
g2 = gen(); print('second time')  # no stop will be printed because we haven't hit the finally clause yet
def gen():
    try:
        while True:
            yield 1
    finally:
        print("stop")

g = gen(); print('first time')
print(next(g))
g = gen(); print('second time')   # stop will be printed when the first object g was assigned to is garbage collected
4 голосов
/ 09 мая 2019

Цикл завершается, когда генератор закрывается, что происходит автоматически, если вы не сохраните ссылку на него. Как только это произойдет, оператор try гарантирует, что блок finally будет выполнен до того, как объект генератора будет собран мусором. Для сравнения:

>>> next(gen())
stop
1

с

>>> x = gen()
>>> next(x)
1
...