"yield from iterable" против "return iter(iterable)"

При переносе (внутреннего) итератора часто приходится перенаправлять __iter__ метод к основному повторяемому. Рассмотрим следующий пример:

class FancyNewClass(collections.Iterable):
    def __init__(self):
        self._internal_iterable = [1,2,3,4,5]

    # ...

    # variant A
    def __iter__(self):
        return iter(self._internal_iterable)

    # variant B
    def __iter__(self):
        yield from self._internal_iterable

Есть ли существенная разница между вариантом A и B? Вариант А возвращает объект итератора, который был запрошен через iter() из внутреннего повторяемого. Вариант B возвращает объект-генератор, который возвращает значения из внутренней итерации. Является ли один или другой предпочтительным по какой-то причине? В collections.abc yield from версия используется. return iter() Вариант - это шаблон, который я использовал до сих пор.

1 ответ

Решение

Единственное существенное отличие состоит в том, что происходит, когда исключение вызывается из итерируемого. С помощью return iter() ваш FancyNewClass не будет отображаться при отслеживании исключений, тогда как при yield from будет. Как правило, полезно иметь как можно больше информации о трассировке, хотя могут быть ситуации, когда вы хотите скрыть свою оболочку.

Другие отличия:

  • return iter должен загрузить имя iter от глобальных переменных - это потенциально медленно (хотя вряд ли может существенно повлиять на производительность) и может быть испорчено (хотя любой, кто перезаписывает глобальные переменные, заслуживает того, что они получают).

  • С yield from Вы можете вставить другие yield выражения до и после (хотя вы могли бы в равной степени использовать itertools.chain).

  • Как представлено, yield from Форма отбрасывает любое возвращаемое значение генератора (т.е. raise StopException(value), Вы можете исправить это, написав вместо return (yield from iterator),

Вот тест, сравнивающий разборку двух подходов, а также показывающий трассировки исключений: http://ideone.com/1YVcSe

С помощью return iter():

  3           0 LOAD_GLOBAL              0 (iter)
              3 LOAD_FAST                0 (it)
              6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
              9 RETURN_VALUE
Traceback (most recent call last):
  File "./prog.py", line 12, in test
  File "./prog.py", line 10, in i
RuntimeError

С помощью return (yield from):

  5           0 LOAD_FAST                0 (it)
              3 GET_ITER
              4 LOAD_CONST               0 (None)
              7 YIELD_FROM
              8 RETURN_VALUE
Traceback (most recent call last):
  File "./prog.py", line 12, in test
  File "./prog.py", line 5, in bar
  File "./prog.py", line 10, in i
RuntimeError
Другие вопросы по тегам