Médio Python

Iterador Fibonacci com classe

Enunciado

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.

Requisitos

  • A classe deve ter __iter__ que retorna self.
  • __next__ deve retornar o próximo número de Fibonacci e atualizar o estado interno.
  • Após n números, __next__ deve levantar StopIteration.
  • O uso em um for deve imprimir os n primeiros números.

Código inicial

class Fibonacci:
    def __init__(self, n):
        # inicialize atributos
        pass

    def __iter__(self):
        pass

    def __next__(self):
        pass

# Teste:
for num in Fibonacci(8):
    print(num)

Saída esperada

0
1
1
2
3
5
8
13
Ver dica

Mantenha dois atributos para os últimos valores (ex.: a=0, b=1) e um contador de quantos já foram gerados. A cada chamada, retorne a e atualize a, b = b, a+b.

Mostrar solução
class Fibonacci:
    """Iterador que gera os n primeiros números de Fibonacci."""
    def __init__(self, n):
        self.n = n          # quantos números gerar
        self.gerados = 0    # contador de quantos já foram produzidos
        self.a = 0          # primeiro valor
        self.b = 1          # segundo valor

    def __iter__(self):
        return self         # o próprio objeto é o iterador

    def __next__(self):
        if self.gerados >= self.n:
            raise StopIteration  # sinaliza fim da iteração
        valor = self.a
        self.a, self.b = self.b, self.a + self.b  # avança a sequência
        self.gerados += 1
        return valor

# Teste:
for num in Fibonacci(8):
    print(num)

Passo a passo

  1. O construtor guarda n (quantidade desejada), zera o contador gerados e inicializa a=0, b=1.
  2. __iter__ retorna self, pois o objeto já é um iterador.
  3. __next__ verifica se já geramos n números; se sim, levanta StopIteration.
  4. Caso contrário, guarda o valor atual a para retornar.
  5. Atualiza a e b com a, b = b, a + b, avançando a sequência.
  6. Incrementa gerados e retorna o valor guardado.
  7. O for consome o iterador até StopIteration e imprime cada número.

Por que funciona

O protocolo de iteração exige __iter__ e __next__. Ao implementá-los, a classe se comporta como qualquer iterável nativo. O for chama iter() uma vez e depois next() repetidamente; quando __next__ levanta StopIteration, o laço termina sem erro.

Erros comuns

  • Não levantar StopIteration: o for entra em loop infinito.
  • Atualizar a e b na ordem errada: a = b; b = a + b usa o novo a e gera valores incorretos. Use atribuição múltipla.
  • Esquecer de incrementar gerados: o iterador nunca termina.
  • Fazer __iter__ retornar uma lista em vez de self: quebra o protocolo de iterador.

Outra forma de resolver

Usando um gerador, o código fica mais curto:

def fibonacci(n):
    a, b = 0, 1
    for _ in range(n):
        yield a
        a, b = b, a + b

Prefira o gerador quando não precisar de estado explícito ou métodos adicionais.

Saída esperada

0
1
1
2
3
5
8
13