Módulo 13 - Geradores e iteradores

Encadeando geradores

11 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Passar a saída de um gerador como entrada de outro.
  • Montar um pipeline de dados com etapas encadeadas.
  • Entender que o fluxo é puxado item por item, sob demanda.
  • Escrever etapas pequenas, cada uma com uma responsabilidade.

A saída de um vira a entrada de outro

Um gerador consome um iterável, e um gerador também é um iterável. Junte essas duas verdades e você chega a uma ideia poderosa: o que sai de um gerador pode entrar em outro. Encadeando vários, você constrói um pipeline, uma linha de montagem em que cada etapa recebe o fluxo, faz a sua parte e passa adiante. Uma etapa filtra as linhas vazias, a próxima transforma texto em número, a seguinte descarta os negativos. Em nenhum momento a coleção inteira existe na memória: apenas o item que está passando naquele instante. É um dos padrões mais elegantes do Python para processar dados.

O exemplo a seguir monta um pipeline de três etapas sobre uma lista de textos. A primeira etapa converte cada texto em número; a segunda mantém apenas os positivos; a terceira dobra cada valor. Repare que cada função geradora recebe a anterior como fonte, e que nada acontece até o for final começar a puxar os itens. É o for que dá a partida: ele pede um item à última etapa, que pede à do meio, que pede à primeira, que lê a fonte. Um pedido percorre a linha de trás para frente, e um item volta atravessando todas as etapas.

def para_numero(textos):
    for t in textos:
        yield int(t)

def so_positivos(numeros):
    for n in numeros:
        if n > 0:
            yield n

def dobrar(numeros):
    for n in numeros:
        yield n * 2

brutos = ["3", "-1", "5", "0", "8"]

pipeline = dobrar(so_positivos(para_numero(brutos)))
print(list(pipeline))   # [6, 10, 16]

Três geradores encadeados: converter, filtrar e dobrar. O fluxo passa item por item.

Como o fluxo corre pelo pipeline

Vale visualizar o caminho de um único item para entender por que o pipeline é tão econômico. Quando o for pede o primeiro valor, dobrar pede um número a so_positivos, que pede a para_numero, que lê o primeiro texto, 3, e o converte em 3. Esse 3 passa por so_positivos, que o aprova por ser positivo, e chega a dobrar, que devolve 6. Só então o for recebe o 6 e o imprime. Apenas depois disso o segundo item começa a jornada. Ou seja: um item de cada vez percorre o pipeline inteiro, e nunca há uma lista intermediária de todos os convertidos ou de todos os positivos.

Esse estilo tem duas vantagens que se reforçam. A primeira é a memória: como o fluxo é puxado item a item, um arquivo de milhões de linhas passa pelo pipeline gastando a memória de uma linha por vez. A segunda é a clareza: cada etapa é pequena, tem um nome que explica sua função e pode ser testada isoladamente. Trocar a ordem, remover uma etapa ou inserir outra é uma edição local, sem tocar no resto. A biblioteca padrão inclui o módulo itertools, cheio de peças de pipeline prontas, como chain para emendar sequências e islice para limitar a quantidade, que combinam de forma natural com os seus próprios geradores.

Consolidando o pipeline

Encadear geradores é montar uma linha de montagem preguiçosa. Cada etapa recebe um fluxo, aplica uma transformação simples e passa adiante, e nada roda até o consumo final puxar os itens. O resultado é um jeito de processar grandes volumes de dados que é ao mesmo tempo leve na memória e fácil de ler, porque a lógica fica dividida em pedaços pequenos e nomeados. Esse padrão é a ponte direta para a prática final do módulo, onde você vai encadear a leitura de um arquivo grande com um filtro, tudo linha a linha.

Teste rápido

Em um pipeline de geradores encadeados, como os dados percorrem as etapas?

Perguntas frequentes

O que é um pipeline de dados com geradores?
É uma sequência de etapas em que a saída de um gerador alimenta a entrada do próximo. Cada etapa filtra ou transforma o fluxo e passa adiante, processando um item por vez. Como nada é materializado no meio, o pipeline trata grandes volumes gastando pouca memória e mantendo a lógica dividida em partes pequenas.
Qual etapa do pipeline roda primeiro?
O consumo final é quem dá a partida. Ao pedir um item, o pedido percorre as etapas de trás para frente até a fonte, e o item volta atravessando cada etapa na ordem. Ou seja, o código é escrito de fora para dentro, mas o dado flui da fonte até o consumo, um item de cada vez.
Por que dividir em várias etapas em vez de fazer tudo numa função?
Etapas pequenas, cada uma com uma responsabilidade, são mais fáceis de ler, testar e reordenar. Você pode reaproveitar so_positivos em outro pipeline, remover uma etapa sem mexer nas outras ou inserir uma nova no meio. É a mesma vantagem de funções pequenas, aplicada ao processamento de fluxo.
O pipeline guarda os resultados intermediários na memória?
Não. Como cada etapa é um gerador preguiçoso, não existe uma lista de todos os convertidos ou de todos os filtrados. Apenas o item que está passando naquele instante ocupa memória. É isso que permite processar arquivos ou fluxos enormes sem estourar a memória.
O módulo itertools ajuda a montar pipelines?
Bastante. Ele traz peças prontas que combinam com seus geradores, como chain para emendar várias sequências em uma, islice para pegar só uma fatia e takewhile para parar sob uma condição. Todas são preguiçosas, então encaixam no pipeline sem quebrar a economia de memória.
Posso encadear generator expressions em vez de funções geradoras?
Pode, e às vezes fica ótimo para etapas simples: positivos = (n for n in numeros if n > 0). Para lógicas mais longas ou reutilizáveis, funções geradoras com yield ficam mais legíveis e testáveis. Vale misturar as duas formas conforme a etapa pede.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.