Выход из генератора, в котором есть оператор возврата <value>

У меня есть генератор с return value утверждение в нем. Если я использую следующий на нем, я получаю Stopiteration: value от этого, как и ожидалось. Однако, когда я использую yield from value потерян.

In [1]: def test():
   ...:     return 1
   ...:     yield 2
   ...:

In [2]: t = test()

In [3]: t
Out[3]: <generator object test at 0x000000000468F780>

In [4]: next(t)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-4-9494367a8bed> in <module>()
----> 1 next(t)

StopIteration: 1

In [5]: def new():
   ...:     yield from test()
   ...:

In [6]: n = new()

In [7]: n
Out[7]: <generator object new at 0x00000000050F23B8>

In [8]: next(n)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-8-1c47c7af397e> in <module>()
----> 1 next(n)

StopIteration:

Есть ли способ сохранить value когда используешь yield from? Это работает как задумано или, может быть, это ошибка?

1 ответ

Решение

Получив значение, отправленное суб-генератором в yield from заявление.

Принятие цитаты из PEP 380 - Синтаксис для делегирования субгенератору:

Значение yield from выражение является первым аргументом StopIteration исключение, вызываемое итератором, когда оно завершается.

Итак, с небольшим изменением, res в new генератор будет содержать значение StopIteration поднял из test subgenerator:

def new():
   res = yield from test()
   return res

Теперь когда next(n) после выполнения вы получите значение в сообщении об исключении:

n = new()

next(n)
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-39-1c47c7af397e> in <module>()
----> 1 next(n)

StopIteration: 1

Да, и, как дополнение, вы, конечно, можете получить возвращаемое значение без его инкапсуляции в StopIteration объект с помощью yield снова:

def new():
    res = yield from test()
    yield res

Сейчас звоню next(new()) вернет значение, возвращенное из test():

next(new())
Out[20]: 1
Другие вопросы по тегам