About me

About

2013-10-04

Pythonices, obter vários valores de uma lista.

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.

1 comentário:

  1. Nota: no último exemplo, a função "consume" pode ser logo:

    def consume(f): return itertools.izip_longest(f,f,f, fillvalue=None)

    ResponderEliminar