См. "Примерно эквивалентную" реализацию itertools.tee
, включенную в документацию:
def tee(iterable, n=2):
it = iter(iterable)
deques = [collections.deque() for i in range(n)]
def gen(mydeque):
while True:
if not mydeque: # when the local deque is empty
try:
newval = next(it) # fetch a new value and
except StopIteration:
return
for d in deques: # load it to all the deques
d.append(newval)
yield mydeque.popleft()
return tuple(gen(d) for d in deques)
По существу, tee
сохраняет очередь для каждого сгенерированного итератора. Когда запрашивается новое значение, если в очереди итератора что-то есть, оно получает оттуда следующее значение, и если очередь пуста, он вызывает next
в исходном итераторе один раз и добавляет результат в каждую очередь. Это означает, что сгенерированные значения «кэшируются» и возвращаются каждым итератором вместо дублирования работы по созданию элемента.
Более того, tee
в общем случае будет вести себя не так, как вы ожидаете, поскольку tee
не может знать, как вообще делать копии итератора. Подумайте, например, о текстовом файле. Как только вы прочитаете одну строку в принципе, вы не сможете вернуться назад (в простом последовательном доступе), и не будет такой вещи, как «дублирование файлового итератора» как такового (для эмуляции чего-то подобного вам потребуется несколько обработчиков файлов или поиск), поэтому Вы просто сохраняете прочитанные строки и возвращаете их позже в других итераторах.