Coffee, tee or me

Итератор, как известно, выдает значения по одному (например, методом next), и его нельзя «отмотать» назад. Это означает, что получать все подряд значения из итератора может только один потребитель. Однако, если несколько потребителей хотят читать из одного итератора, его можно разделить с помощью функции itertools.tee. Кстати, tee переводится как тройник (тройник похож на букву Т).

tee принимает исходный итератор и число – количество новых итераторов, на которые разделится исходный, а возвращает кортеж из новых итераторов. При этом извлечение значений из одного из итераторов не влияет на остальные.

📎 Пример:

from itertools import tee

def source():
    for i in range(5):
        print(f'next is {i}')
        yield i

# три потребителя
coffee, tea, me = tee(source(), 3)

# первый берет два числа
next(coffee); next(coffee)
# второй одно
next(tea)
# третий - все
for i in me:
    ...

Вывод:

next is 0
next is 1
next is 2
next is 3
next is 4

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

Предостережения:

1. Исходный итератор не следует итерировать, иначе производные итераторы лишатся некоторых значений. 

2. Механизм tee таков, что он хранит в памяти извлеченные элементы, чтобы остальные потребители могли их получить, даже если исходный итератор уже сместился. Поэтому, если элементов много или они большие, это может серьезно повлиять на расход памяти.

Полный пример кода (плюс моя реализация tee на скорую руку) – по ссылке.

🐉 Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈