Da trilha de Python Este conceito ainda não saiu como card do dia. ir para o card de hoje

Python Funções Intermediário

Iteradores e geradores

Em Python, um iterador é um objeto que implementa o protocolo de iteração: os métodos __iter__ (que retorna o próprio iterador) e __next__ (que devolve o próximo item ou levanta StopIteration). Listas, strings e dicionários são iteráveis (têm __iter__), mas não são iteradores em si.

Um gerador é uma forma simples de criar iteradores usando yield em uma função. Quando a função é chamada, ela não executa o corpo imediatamente; em vez disso, retorna um objeto gerador que produz valores sob demanda. Cada yield pausa a função e guarda seu estado, permitindo retomar de onde parou.

Expressões geradoras são como list comprehensions, mas com parênteses: (x * 2 for x in range(5)). Elas não criam a lista inteira na memória; produzem valores um a um, seguindo o princípio da avaliação preguiçosa (lazy evaluation). Isso é essencial para processar grandes volumes de dados ou fluxos infinitos.

Neste card, você verá como implementar seus próprios iteradores, usar yield para criar geradores, escrever expressões geradoras e entender quando a preguiça computacional faz diferença.

Pontos-chave

  • Um iterador implementa __iter__ e __next__; um iterável implementa apenas __iter__.
  • yield pausa a função e a transforma em um gerador, que produz valores sob demanda.
  • Expressões geradoras usam parênteses e não constroem a sequência inteira na memória.
  • A avaliação preguiçosa só calcula o próximo item quando ele é pedido, economizando memória e tempo.
  • for consome qualquer iterável chamando iter() e depois next() até StopIteration.
geradores.py
# Exemplo: iterador manual vs. gerador com yield

class Contador:
    """Iterador que conta de 0 até n-1."""
    def __init__(self, n):
        self.n = n
        self.atual = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.atual >= self.n:
            raise StopIteration
        valor = self.atual
        self.atual += 1
        return valor

# Mesmo comportamento, mas com gerador
def contador_gerador(n):
    atual = 0
    while atual < n:
        yield atual          # pausa e devolve o valor
        atual += 1

# Expressão geradora: não cria lista, calcula sob demanda
quadrados = (x * x for x in range(5))

print("Iterador manual:")
for num in Contador(3):
    print(num)

print("Gerador com yield:")
for num in contador_gerador(3):
    print(num)

print("Expressão geradora:")
for q in quadrados:
    print(q)

Exercícios

  1. 1
    Fácil

    Gerador de números pares

    Escreva uma função geradora pares(n) que produza os números pares de 0 até n-1 (inclusive se n for ímpar). Use yield.

    Resolver
  2. 2
    Médio

    Iterador Fibonacci com classe

    Implemente uma classe Fibonacci que seja um iterador para os n primeiros números de Fibonacci (começando em 0 e 1). A classe deve implementar __iter__ e __next__, levantando StopIteration quando terminar.

    Resolver
  3. 3
    Desafio

    Pipeline preguiçoso com geradores

    Crie um pipeline de processamento usando geradores que:

    1. Leia números de uma lista;
    2. Filtre apenas os pares;
    3. Eleve cada par ao quadrado;
    4. Some apenas os 3 primeiros resultados.

    Implemente funções geradoras separadas para cada etapa e uma expressão geradora para o quadrado. O resultado final deve ser a soma dos 3 primeiros quadrados de pares.

    Resolver

Continue estudando