Как обернуть Iterator в Iterable для повторного использования в питонической форме? - PullRequest
0 голосов
/ 17 января 2019

Введение

У меня есть итератор, например:

from itertools import product

iterator_ = product([1, 2, 3], [7, 8, 9])

Если я попытаюсь повторить итератор более одного раза, я не смогу, потому что он исчерпан после первой итерации.

Вопрос

Как я могу создать итерацию iterable_ из iterator_, чтобы я мог перебирать итератор столько раз, сколько захочу? Желательно эффективным и питонным способом.

Гадкий раствор / пример

Работает не для всех итераторов - см. Комментарий

До сих пор я смог найти следующее уродливое решение:

from copy import copy
from typing import Iterable, Iterator


class WrappedIterator(Iterable):
    """
    Wraps an iterator in an iterable

    This allows to iterate over a given iterator more than once. Subsequent
    actions on the given iterator do not have impact due to internal copying.
    """

    def __init__(self, iterator: Iterator):
        self._iterator = copy(iterator)

    def __iter__(self) -> Iterator:
        return copy(self._iterator)

    def __next__(self):
        raise NotImplementedError(
            "One is not supposed to iterate over this object. Instead, "
            "one should produce an iterator from it with `__iter__` and "
            "iterate (as in, call `__next__` on the returned iterator).")

Чтобы следующее позволило мне создать итератор из итератора:

iterable_ = WrappedIterator(iterator_)

# The following does not fail
for _ in range(666):
    assert len(list(iterable_)) > 0

# The following fails on attempt number 1
for i in range(666):
    assert len(list(iterator_)) > 0, f"Failed on attempt {i}"

Другие идеи

Я видел некоторые сообщения на itertools.tee или itertools.zip, но я не уверен, что эти решения могут быть эффективными и достаточно питонными. Но я наверняка могу ошибаться в них.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...