Programador Leigo
Python 10 min leitura 13 MAR 2026

Geradores e Iteradores em Python: guia com exemplos

Aprenda a processar milhões de dados sem estourar a memória. Geradores são o segredo dos programas eficientes.


O problema: tudo na memória de uma vez

Imagine que você precisa processar um arquivo com 10 milhões de linhas. O instinto natural é:

# Carrega TUDO na memoria — pode travar o computador
linhas = open("arquivo_gigante.txt").readlines()
for linha in linhas:
    processa(linha)

Com geradores, você processa uma linha por vez, sem nunca carregar tudo na memória:

# Processa uma linha por vez — memoria constante
for linha in open("arquivo_gigante.txt"):
    processa(linha)

Essa é a magia dos iteradores e geradores.


Iteráveis vs Iteradores

Antes de falar de geradores, vamos entender a diferença:

  • Iterável: qualquer coisa que você pode percorrer com for (listas, strings, dicts, arquivos)
  • Iterador: o objeto que controla a iteração, lembrando em qual posição está
lista = [1, 2, 3]           # iteravel
iterador = iter(lista)       # iterador

print(next(iterador))        # 1
print(next(iterador))        # 2
print(next(iterador))        # 3
print(next(iterador))        # StopIteration!

O for faz isso automaticamente: chama iter() no iterável e depois next() até receber StopIteration.


Geradores: iteradores sem esforço

Um gerador é uma função que usa yield em vez de return:

def contagem_regressiva(n):
    while n > 0:
        yield n
        n -= 1

for numero in contagem_regressiva(5):
    print(numero)
# 5, 4, 3, 2, 1

A diferença crucial: a função pausa a cada yield e continua de onde parou quando o próximo valor é pedido. Ela não roda tudo de uma vez.


yield vs return

# Com return — cria a lista inteira na memoria
def quadrados_lista(n):
    resultado = []
    for i in range(n):
        resultado.append(i ** 2)
    return resultado

# Com yield — gera um valor por vez
def quadrados_gerador(n):
    for i in range(n):
        yield i ** 2
# Lista: ocupa memoria proporcional a n
lista = quadrados_lista(1_000_000)      # ~8 MB na memoria

# Gerador: ocupa memoria constante
gerador = quadrados_gerador(1_000_000)  # quase nada na memoria

Generator expressions

Assim como list comprehensions criam listas, generator expressions criam geradores:

# List comprehension — cria lista na memoria
quadrados = [x ** 2 for x in range(1_000_000)]

# Generator expression — gera sob demanda
quadrados = (x ** 2 for x in range(1_000_000))

A única diferença visual: [] vs (). A diferença prática: memória.

import sys

lista = [x ** 2 for x in range(1_000_000)]
gerador = (x ** 2 for x in range(1_000_000))

print(sys.getsizeof(lista))    # ~8 MB
print(sys.getsizeof(gerador))  # ~200 bytes

Quando usar geradores

Processar arquivos grandes

def buscar_erros(caminho):
    with open(caminho) as f:
        for linha in f:
            if "ERROR" in linha:
                yield linha.strip()

for erro in buscar_erros("app.log"):
    print(erro)

Gerar sequências infinitas

def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# Pega os 10 primeiros
from itertools import islice
primeiros = list(islice(fibonacci(), 10))
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

Encadear transformações (pipelines)

def ler_linhas(caminho):
    with open(caminho) as f:
        for linha in f:
            yield linha.strip()

def filtrar_vazias(linhas):
    for linha in linhas:
        if linha:
            yield linha

def para_maiusculo(linhas):
    for linha in linhas:
        yield linha.upper()

# Pipeline — nada e carregado na memoria
linhas = ler_linhas("dados.txt")
linhas = filtrar_vazias(linhas)
linhas = para_maiusculo(linhas)

for linha in linhas:
    print(linha)

Cada etapa processa uma linha por vez. É como uma esteira de fábrica.


yield from: delegando para outro gerador

Quando um gerador precisa produzir valores de outro iterável, use yield from:

def numeros():
    yield from range(3)       # 0, 1, 2
    yield from range(10, 13)  # 10, 11, 12

list(numeros())  # [0, 1, 2, 10, 11, 12]

Sem yield from, você precisaria de um for explícito:

# Equivalente sem yield from
def numeros():
    for n in range(3):
        yield n
    for n in range(10, 13):
        yield n

O módulo itertools

O Python tem um módulo inteiro dedicado a iteradores eficientes:

from itertools import chain, count, cycle, islice, groupby

# chain — junta iteraveis
list(chain([1, 2], [3, 4], [5]))  # [1, 2, 3, 4, 5]

# count — contador infinito
list(islice(count(10, 2), 5))  # [10, 12, 14, 16, 18]

# cycle — repete infinitamente
cores = cycle(["vermelho", "verde", "azul"])
list(islice(cores, 7))
# ['vermelho', 'verde', 'azul', 'vermelho', 'verde', 'azul', 'vermelho']

Cuidados com geradores

Geradores se esgotam

gen = (x for x in range(3))

print(list(gen))  # [0, 1, 2]
print(list(gen))  # [] — ja foi consumido!

Se você precisa iterar mais de uma vez, converta para lista ou crie o gerador novamente.

Não dá para acessar por índice

gen = (x for x in range(10))
# gen[5]  # TypeError! Geradores nao suportam indexacao

Se você precisa de acesso aleatório, use uma lista.


Resumo

Conceito O que faz Quando usar
iter() / next() Protocolo de iteração Entender como for funciona
yield Cria um gerador Processar dados sob demanda
Generator expression () Gerador em uma linha Substituir list comprehension quando memória importa
yield from Delega para outro iterável Compor geradores
itertools Ferramentas para iteradores Combinar, filtrar, agrupar iteráveis

Geradores são um dos recursos mais poderosos do Python. Quando você domina geradores, consegue processar qualquer volume de dados com elegância e eficiência.

Continue lendo

Compartilhar