Вот соответствующий пример из документации модуля itertools :
import itertools
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return zip(a, b)
Для Python 2 itertools.izipвместо zip:
import itertools
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = itertools.tee(iterable)
next(b, None)
return itertools.izip(a, b)
Как это работает:
Сначала создаются два параллельных итератора aи b( tee()вызов), указывающие на первый элемент исходного итератора. Второй итератор bперемещается на 1 шаг вперед ( next(b, None)вызов). В этот момент aуказывает на s0 и bуказывает на s1. Оба aи bмогут обходить исходный итератор независимо - функция izip берет два итератора и создает пары из возвращенных элементов, продвигая оба итератора с одинаковой скоростью.
Одно предостережение: tee()функция создает два итератора, которые могут продвигаться независимо друг от друга, но за это приходится платить. Если один из итераторов продвигается дальше, чем другой, то tee() потребляемые элементы должны оставаться в памяти до тех пор, пока второй итератор тоже их не поглотит (он не может «перемотать» исходный итератор). Здесь это не имеет значения, потому что один итератор всего на 1 шаг впереди другого, но в целом таким образом легко использовать много памяти.
И поскольку tee()может принимать nпараметр, его также можно использовать для более чем двух параллельных итераторов:
def threes(iterator):
"s -> (s0,s1,s2), (s1,s2,s3), (s2, s3,4), ..."
a, b, c = itertools.tee(iterator, 3)
next(b, None)
next(c, None)
next(c, None)
return zip(a, b, c)