Módulo 13 - Geradores e iteradores

Função geradora com yield

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

O que você vai aprender

  • Escrever uma função geradora usando yield.
  • Entender que yield pausa a função em vez de encerrá-la.
  • Comparar o comportamento de yield com o de return.
  • Perceber que chamar a função devolve um gerador, não o resultado pronto.

yield: devolver sem terminar

Na aula anterior você viu que o for precisa de um iterador que responda a next() e levante StopIteration no fim. Escrever isso na mão dá trabalho. O yield é o atalho oficial do Python para criar iteradores sem esse esforço. Basta usar yield dentro de uma função e ela deixa de ser comum: vira uma função geradora. A diferença de mentalidade é grande. Uma função normal calcula tudo e devolve um resultado pronto com return. Uma função geradora produz itens aos poucos, um a cada yield, pausando entre eles.

Pense no yield como um botão de pausa que também entrega algo pela janela. Quando a execução chega a um yield, três coisas acontecem: o valor à direita do yield é entregue a quem está percorrendo, a função congela naquela linha exata, com todas as suas variáveis intactas, e o controle volta para quem pediu o item. No próximo next(), a função descongela e segue da linha seguinte ao yield, como se o tempo não tivesse passado. Esse congelamento e descongelamento é o que dá aos geradores o seu superpoder.

def contagem_regressiva(n):
    while n > 0:
        yield n        # entrega n e pausa aqui
        n = n - 1      # continua daqui no proximo pedido
    print("Fim!")

for numero in contagem_regressiva(3):
    print(numero)

# 3
# 2
# 1
# Fim!

A cada volta do while, yield entrega um número e pausa; o for pede o próximo.

yield e return lado a lado

O contraste com return deixa tudo mais nítido. Uma função com return roda até encontrar o return, devolve aquele valor e acaba: qualquer código depois do return não roda naquela chamada. Uma função com yield pode entregar muitos valores, um por vez, e continua viva entre as entregas. Um return dentro de uma função geradora não devolve valor para o for; ele apenas encerra a geração, equivalendo a um StopIteration. É a diferença entre entregar um pacote fechado e abrir uma torneira que pinga sob demanda.

def com_return():
    return [1, 2, 3]   # calcula tudo e devolve a lista pronta

def com_yield():
    yield 1            # entrega 1 e pausa
    yield 2            # entrega 2 e pausa
    yield 3            # entrega 3 e pausa

print(com_return())        # [1, 2, 3]
print(com_yield())         # <generator object com_yield at 0x...>
print(list(com_yield()))   # [1, 2, 3]

com_return devolve a lista na hora; com_yield devolve um gerador que produz sob demanda.

Repare no detalhe do exemplo: chamar com_yield() não imprime 1, 2 e 3. Ele devolve um objeto gerador, ainda parado, que só produz os valores quando alguém os pede. Foi por isso que envolvemos com list(), que percorre o gerador do início ao fim e junta tudo numa lista. No dia a dia você raramente faz isso, porque o mais comum é percorrer o gerador direto com um for, aproveitando exatamente que ele produz aos poucos. Guardar essa vantagem, produzir sob demanda em vez de tudo de uma vez, é o que a próxima aula explora a fundo.

return

  • Encerra a função na hora
  • Devolve um único resultado pronto
  • Código depois dele não roda
  • Calcula tudo antes de entregar

yield

  • Pausa a função e a mantém viva
  • Entrega vários valores, um por vez
  • A função continua da linha seguinte
  • Produz item a item, sob demanda

Conferindo o entendimento

O ponto para levar desta aula é que yield muda o contrato da função. Ela para de ser algo que roda e devolve um resultado, e passa a ser uma fábrica que entrega itens quando pedidos, pausando entre eles. Chamar a função só constrói a fábrica, o gerador; nada roda até você começar a puxar os itens com um for ou com next(). Esse detalhe confunde no começo e vale fixar bem, porque é a base de todo o resto do módulo, incluindo as generator expressions e os pipelines de geradores encadeados.

Teste rápido

O que acontece quando a execução de uma função geradora chega a um yield?

Perguntas frequentes

Uma função pode ter yield e return juntos?
Pode. Se há pelo menos um yield, a função é geradora. Um return dentro dela não devolve valor para o for: ele só encerra a geração, funcionando como um fim antecipado, equivalente a StopIteration. Você usa return sem valor quando quer parar de produzir itens antes do fim natural.
Por que chamar a função geradora não roda o código dela?
Porque o objetivo é produzir sob demanda. Chamar a função constrói e devolve o objeto gerador, ainda parado no começo. O corpo só avança quando você pede itens, com um for ou com next(). É esse adiamento que permite trabalhar com sequências grandes sem calcular tudo de uma vez.
Posso ter vários yield na mesma função?
Sim, e é comum. Cada yield que a execução alcança entrega um item e pausa. Eles podem estar em sequência, dentro de laços ou dentro de condições. A função vai entregando valores na ordem em que os yield são executados, retomando de onde parou a cada pedido.
Como transformo o resultado de um gerador em lista?
Basta envolver o gerador com list(), como em list(minha_funcao()). Isso percorre o gerador do início ao fim e junta todos os itens numa lista. Faça isso apenas quando precisar mesmo de todos os itens na memória; muitas vezes percorrer com for é melhor.
yield deixa o código mais lento?
Não, ao contrário em muitos casos. Como o gerador produz item por item, ele evita construir listas gigantes na memória e permite começar a usar os primeiros resultados antes de calcular os últimos. Para sequências grandes, costuma ser mais rápido a sentir e muito mais leve na memória.
Qual a diferença prática para uma função que devolve uma lista?
A função com return monta a lista inteira antes de devolver, ocupando memória proporcional ao tamanho. A geradora entrega um item de cada vez, sem guardar todos. Se você só vai percorrer os itens uma vez, o gerador faz o mesmo trabalho gastando muito menos memória.

Fontes

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