Aqui está um exemplo relevante dos documentos do módulo 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)
Para Python 2, você precisa, em itertools.izipvez de 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)
Como isso funciona:
Primeiro, dois iteradores paralelos ae bsão criados (a tee()chamada), ambos apontando para o primeiro elemento do iterável original. O segundo iterador bé movido 1 passo à frente (a next(b, None)) chamada. Nesse ponto, aaponte para s0 e baponte para s1. Ambos ae bpodem atravessar o iterador original independentemente - a função izip pega os dois iteradores e faz pares dos elementos retornados, avançando os dois iteradores no mesmo ritmo.
Uma ressalva: a tee()função produz dois iteradores que podem avançar independentemente um do outro, mas tem um custo. Se um dos iteradores avançar mais que o outro, será tee() necessário manter os elementos consumidos na memória até o segundo iterador consumi-los também (ele não pode 'rebobinar' o iterador original). Aqui não importa, porque um iterador está apenas um passo à frente do outro, mas, em geral, é fácil usar muita memória dessa maneira.
E como tee()pode assumir um nparâmetro, isso também pode ser usado para mais de dois iteradores paralelos:
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)