Objectivo: processar grupos de 3 linhas seguidas de um ficheiro.
Soluções…
Juntar as 3 no loop usando informação de estado
with file("pythonices") as f:
lines = []
for line in f:
lines.append(line)
if len(lines) == 3:
process(lines)
del lines[:]
A lista lines
é usada para manter a contagem das linhas lidas. Chegando a 3, processa-as.
- a lógica de juntar as linhas torna o ciclo pouco claro;
- obriga a manter estado explícito.
Obter as 3 dentro do ciclo
with file("pythonices") as f:
while 1:
try:
l1 = next(f)
l2 = next(f)
l3 = next(f)
process([l1, l2, l3])
except StopIteration:
break
- a obtenção de linhas é agora linear;
- a construção é mais simples;
- mas usa-se o bloco
try-except
para controlar a paragem do ciclo.
Alterando a source para fornecer logo as 3 linhas
with file("pythonices") as f:
for l1,l2,l3 in zip(f,f,f):
process([l1,l2,l3])
Mais simples e legível.
E se o ficheiro não for múltiplo de 3? Os casos anteriores descartam as linhas extras. Com a última solução podemos controlar esse comportamento facilmente mexendo apenas na “fonte”. Neste caso usando itertools.izip_longest
que funciona como o zip
, só que convertendo os valores extra – caso os haja – num valor pré-definido.
import itertools
with file("pythonices") as f:
for l1,l2,l3 in itertools.izip_longest(f,f,f, fillvalue=None):
process([l1,l2,l3])
A vantagem desta solução face às anteriores foi ter separado e abstraído a tarefa em duas instâncias: a obtenção das fontes e o seu processamento.
Criando funções que representam explicitamente as abstracções fica:
import itertools
def process(x): print x
def consume(f):
for l1,l2,l3 in itertools.izip_longest(f,f,f, fillvalue=None):
yield l1,l2,l3
with file("pythonices") as f:
for l1,l2,l3 in consume(f):
process([l1,l2,l3])
De notar que não foram as funções que criaram as abstracções. As funções são estrutura. A primeira solução desta secção tem o mesmo nível de abstracção que esta última. Posso voltar no futuro ao tema abstracção.
Nota: no último exemplo, a função "consume" pode ser logo:
ResponderEliminardef consume(f): return itertools.izip_longest(f,f,f, fillvalue=None)