Введение
У меня есть итератор, например:
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
, но я не уверен, что эти решения могут быть эффективными и достаточно питонными. Но я наверняка могу ошибаться в них.