Geradores e Iteradores em Python – Trabalhando com Grandes Volumes de Dados

Quando lidamos com grandes volumes de dados, a eficiência no uso de memória e processamento se torna crucial. Imagine tentar carregar um arquivo de 10 GB em RAM de uma só vez — isso pode travar até mesmo computadores potentes.

É aqui que entram os iteradores e geradores, dois recursos fundamentais do Python que permitem processar dados sob demanda, sem precisar armazenar tudo na memória de uma só vez.

Neste artigo, você vai aprender:


🔹 1. O que são Iteradores?

Um iterador é um objeto em Python que pode ser percorrido elemento por elemento.
Ele implementa dois métodos especiais:

  • __iter__() → retorna o próprio iterador.

  • __next__() → retorna o próximo item ou gera StopIteration quando acaba.

Exemplo simples:

numeros = [1, 2, 3]
it = iter(numeros)

print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# print(next(it)) → StopIteration

Ou seja: um iterador entrega os valores sob demanda, um de cada vez.


🔹 2. Loops e Iteradores

Todo for em Python, internamente, usa iteradores:

for letra in "Python":
    print(letra)

Por trás dos panos, isso equivale a:

it = iter("Python")
while True:
    try:
        letra = next(it)
        print(letra)
    except StopIteration:
        break

🔹 3. O que são Geradores?

Um gerador é uma forma especial de criar iteradores de maneira mais simples e legível.
Ele usa a palavra-chave yield, que pausa a execução da função e retorna um valor, continuando dali na próxima chamada.

Exemplo:

def contador(limite):
    n = 1
    while n <= limite:
        yield n
        n += 1

for num in contador(5):
    print(num)

Saída:

1
2
3
4
5

⚡ Diferente de funções normais, geradores não retornam todos os dados de uma vez, mas sob demanda.


🔹 4. Diferença entre Lista, Iterador e Gerador

Lista

  • Armazena todos os elementos na memória.

  • Bom para conjuntos pequenos.

nums = [x for x in range(10**6)]

Iterador/Gerador

  • Calcula elementos na hora que são pedidos.

  • Economiza memória.

nums = (x for x in range(10**6))  # expressão geradora

📌 Diferença prática:

import sys

lista = [x for x in range(1000000)]
gerador = (x for x in range(1000000))

print(sys.getsizeof(lista))    # ocupa muita memória
print(sys.getsizeof(gerador))  # ocupa pouquíssima memória

🔹 5. Geradores Infinitos

Você pode criar geradores infinitos, que só param quando você decide:

def naturais():
    n = 1
    while True:
        yield n
        n += 1

it = naturais()
for _ in range(5):
    print(next(it))

Saída:

1
2
3
4
5

Isso seria impossível com listas (memória infinita seria necessária).


🔹 6. Casos de Uso Reais

  1. Leitura de arquivos grandes

def ler_linhas(arquivo):
    with open(arquivo, "r", encoding="utf-8") as f:
        for linha in f:
            yield linha.strip()

for linha in ler_linhas("dados.txt"):
    print(linha)

Assim, você lê linha por linha sem carregar todo o arquivo.


  1. Processamento de dados em stream (ex.: logs, sensores, APIs em tempo real).

import time

def stream_logs():
    while True:
        yield f"Log gerado em {time.time()}"
        time.sleep(1)

for log in stream_logs():
    print(log)

  1. Filtragem e pipelines de dados

def quadrados(nums):
    for n in nums:
        yield n * n

dados = range(1, 6)
for q in quadrados(dados):
    print(q)

🔹 7. Expressões Geradoras

Parecidas com listas por compreensão, mas economizam memória:

lista = [x**2 for x in range(5)]     # lista
gerador = (x**2 for x in range(5))   # gerador

print(lista)        # [0, 1, 4, 9, 16]
print(list(gerador)) # [0, 1, 4, 9, 16]

🔹 8. Biblioteca itertools

Python oferece a biblioteca itertools para manipulação avançada de iteradores:

import itertools

# contagem infinita
for i in itertools.count(10, 2):
    if i > 20:
        break
    print(i)  # 10, 12, 14, 16, 18, 20

# ciclo infinito
ciclo = itertools.cycle("ABC")
for _ in range(5):
    print(next(ciclo))  # A B C A B

Outras funções úteis:

  • islice (fatiamento de iteradores)

  • chain (concatenação)

  • combinationspermutationsproduct


🔹 9. Boas Práticas com Iteradores e Geradores

✅ Use listas quando precisar acessar elementos aleatoriamente ou manipular várias vezes.
✅ Use geradores quando lidar com fluxos grandes ou infinitos de dados.
✅ Combine geradores para criar pipelines eficientes.
✅ Sempre documente se sua função retorna lista ou gerador (o comportamento é diferente).
✅ Lembre-se que geradores se esgotam — depois de consumidos, precisam ser recriados.


🔹 10. Conclusão

Iteradores e geradores são ferramentas poderosas para processamento eficiente de dados em Python.

  • Iteradores permitem consumir dados passo a passo.

  • Geradores facilitam a criação de iteradores com yield.

  • Eles reduzem drasticamente o uso de memória em grandes volumes de dados.

  • Usados em conjunto com itertools e expressões geradoras, permitem criar pipelines elegantes e eficientes.

💡 Próximo passo prático: tente reescrever scripts que usam listas enormes para usar geradores — você verá a diferença de performance e consumo de memória.

Comentários

Postagens mais visitadas deste blog

Manipulação de Arquivos no C#: Como Ler, Escrever e Trabalhar com Arquivos de Forma Simples

Gerando Relatórios em PDF com Python (ReportLab e FPDF)

C# e Banco de Dados: Como Conectar e Realizar Operações com SQL Server