Бесконечный генератор для итерируемого объекта

40. Бесконечный генератор для итерируемого объекта

Условие задачи:
Написать бесконечный генератор, который принимает любой итерируемый объект и по кругу возвращает его элементы без завершения.

Пример:

# [1, 2, 3] -> 1, 2, 3, 1, 2, 3, ...

from typing import Iterable

def my_gen(inp_value: Iterable):
    ...
Спойлеры к решению
Подсказки
  • Нужна функция-генератор, значит внутри должен быть yield.
  • Нужно пройти по переданному итерируемому объекту.
  • После последнего элемента генератор должен снова начать с первого.
  • Для этого можно использовать бесконечный цикл while True.
  • Чтобы можно было повторно проходить по данным, входной объект лучше сохранить в tuple или list.
  • Если передан пустой итерируемый объект, бесконечно возвращать нечего.
Решение
from typing import Iterable, Iterator, TypeVar


T = TypeVar("T")


def my_gen(inp_value: Iterable[T]) -> Iterator[T]:
    values = tuple(inp_value)

    if not values:
        return

    while True:
        for item in values:
            yield item

Пример использования:

gen = my_gen([1, 2, 3])

for _ in range(10):
    print(next(gen), end=" ")

Результат:

1 2 3 1 2 3 1 2 3 1

Функция сначала сохраняет элементы входного итерируемого объекта в tuple:

values = tuple(inp_value)

Это нужно, чтобы по элементам можно было проходить снова и снова. Затем запускается бесконечный цикл:

while True:

Внутри него функция каждый раз проходит по сохранённым значениям и отдаёт элементы через yield.

Альтернативный короткий вариант через стандартную библиотеку:

from itertools import cycle
from typing import Iterable, Iterator, TypeVar


T = TypeVar("T")


def my_gen(inp_value: Iterable[T]) -> Iterator[T]:
    return cycle(inp_value)

itertools.cycle() делает то же самое: бесконечно возвращает элементы итерируемого объекта по кругу.