Entenda a mágica dos Generators. (#python, #dev, #generator, #iterator)

Bem-vindo ao mundo dos geradores em Python! Esses pequenos objetos úteis são como o filho de uma lista e uma função – eles permitem que você itere uma sequência de valores, mas, ao contrário das listas, eles não armazenam todos os valores na memória de uma só vez. Isso os torna uma ótima ferramenta para trabalhar com grandes conjuntos de dados ou realizar cálculos caros, um valor por vez.


Introdução

Os geradores Python são um tipo de iterable, o que significa que eles podem ser usados em um loop for para iterar sobre uma sequência de valores. No entanto, ao contrário das listas ou tuplas, os geradores não armazenam todos os valores na memória de uma só vez. Em vez disso, eles geram os valores dinamicamente à medida que são necessários, o que os torna uma opção mais eficiente e de memória amigável para trabalhar com grandes conjuntos de dados ou realizar cálculos complicados/pesados.

Para criar um generator em Python, você pode usar a palavra-chave yield em uma função. Quando a função é chamada, ela será executada até encontrar uma instrução yield, neste momento ela retornará o valor da expressão seguinte à palavra-chave yield e pausará a execução. Na próxima vez que o gerador for chamado, ele retomará a execução do ponto em que parou e continuará até encontrar outra instrução yield ou atingir o final da função.

Os geradores são uma ferramenta poderosa e eficiente para trabalhar com grandes conjuntos de dados ou realizar cálculos pesados, um valor por vez. Eles podem ajudar você a economizar memória e melhorar o desempenho do seu código, especialmente ao trabalhar com grandes conjuntos de dados ou cálculos complexos.

 

Vantagens e Desvantagens

Vantagens:

  • Eficiência: Geradores são mais eficientes que listas ou tuplas porque não armazenam todos os valores na memória de uma vez. Isso os torna uma boa escolha para trabalhar com grandes conjuntos de dados ou realizar cálculos caros, pois eles podem economizar memória e melhorar o desempenho do seu código.
  • Uso de memória: conforme mencionado acima, os geradores não armazenam todos os valores na memória de uma só vez, o que pode ser uma vantagem significativa ao trabalhar com grandes conjuntos de dados. Isso pode ajudar a reduzir o uso de memória do seu programa e evitar que ele trave devido à falta de memória disponível.
  • Simplicidade do código: os geradores podem ajudar a simplificar seu código, permitindo que você escreva uma única função que gere os valores necessários, em vez de criar uma lista ou tupla e armazenar todos os valores na memória. Isso pode tornar seu código mais fácil de ler e manter.

 

Desvantagens:

  • Imutabilidade: Os geradores são imutáveis, o que significa que, uma vez criados, não é possível modificar os valores que contêm. Isso pode ser uma limitação se você precisar atualizar ou alterar os valores no gerador.
  • Uso único: Os geradores só podem ser iterados uma vez, o que significa que depois de iterar todos os valores no gerador, você não pode voltar e iterar sobre eles novamente. Isso pode ser uma limitação se você precisar repetir os mesmos valores várias vezes.
  • Falta de indexação: os geradores não suportam indexação, o que significa que você não pode acessar valores específicos no gerador usando um índice como faria com uma lista ou tupla. Isso pode ser uma limitação se você precisar acessar valores específicos no gerador.

No geral, os geradores podem ser uma ferramenta útil para trabalhar com grandes conjuntos de dados ou realizar cálculos caros, mas eles têm algumas limitações que você deve considerar antes de decidir usá-los em seu código.

 

Quando utilizar

Você deve usar geradores quando estiver trabalhando com um grande conjunto de dados ou realizando operações pesadas que você só precisa iterar uma vez.

Por exemplo, digamos que você tenha um arquivo CSV contendo milhões de registros e precise processar os dados e realizar alguns cálculos em cada registro. Usar um generator para iterar os registros um por vez seria mais eficiente do que ler o arquivo inteiro em uma lista ou tupla e armazenar todos os registros na memória de uma vez. Isso economizaria memória e melhoraria o desempenho do seu programa.

 

Quando não utilizar

Você não deve usar generators quando precisar modificar os valores no iterável ou quando precisar iterar os mesmos valores várias vezes.

Por exemplo, digamos que você tenha uma lista de números inteiros e precise elevar ao quadrado cada valor da lista. Você poderia usar um gerador para iterar na lista e elevar ao quadrado cada valor, mas como os geradores são imutáveis, você não seria capaz de atualizar os valores no gerador. Em vez disso, você precisaria criar uma nova lista ou tupla para armazenar os valores ao quadrado.

Nesse cenário, seria mais apropriado usar uma lista ou tupla e modificar os valores no local, em vez de usar um gerador. Isso permitiria modificar os valores no iterável e iterar sobre os mesmos valores várias vezes, se necessário.

 

Código

Aqui está um exemplo de um gerador em Python que gera os primeiros n números pares:


def even_number_generator(n: int) -> Iterator[int]:
    i = 0
    while i < n:
        yield 2 * i
        i += 1

# Generate the first 5 even numbers
even_numbers = even_number_generator(5)

# Print the even numbers
for num in even_numbers:
    print(num)

Esse código define uma função geradora chamada even_number_generator que recebe um inteiro n como argumento e retorna um iterador de inteiros usando a palavra-chave yield. O gerador cria os primeiros n números pares começando em 0 e incrementando em 2 cada vez que é chamado.

Para usar o gerador, chamamos a função even_number_generator e passamos o número de números pares que queremos gerar. Isso retorna um objeto gerador que podemos iterar usando um loop for.

Neste exemplo, o gerador irá gerar e imprimir os primeiros 5 números pares: 0, 2, 4, 6, 8.

O tipo de dados do argumento n é int e o tipo de dados dos valores retornados pelo gerador é Iterator[int], onde Iterator é uma dica de tipo que indica que o gerador retorna um iterador de inteiros.

 

Comparação para a galera .net

Os generators do Python e os IEnumerable do C# são semelhantes, pois ambos permitem iterar uma sequência de valores sem armazenar todos os valores na memória de uma só vez. Isso os torna uma ferramenta útil para trabalhar com grandes conjuntos de dados ou realizar cálculos caros um valor por vez.

Existem algumas diferenças importantes entre os dois:

  • Sintaxe: No C# você pode implementar um IEnumerable criando uma classe que implementa a interface IEnumerable e inclui um método chamado GetEnumerator. Em Python, você pode criar um gerador usando a palavra-chave yield em uma função.
  • Tipo de retorno: No C#, o tipo de retorno de um IEnumerable é IEnumerable<T>, onde T é o tipo dos valores que estão sendo enumerados. Em Python, o tipo de retorno de um gerador é um iterador.

 

Um ponto em comum entre os dois:

  • Imutabilidade: No C#, IEnumerable é imutável, o que significa que você não pode modificar os valores na sequência depois de criada. Em Python, os geradores também são imutáveis.

 

Espero ter ajudado!

The following two tabs change content below.
Arquiteto de Software e Desenvolvedor Backend (quase Fullstack), geralmente trabalho com C#, PowerShell, Python, Golang, bash e Unity (esse é mais por hobby). Estou sempre buscando algo novo para aprender, adicionando novas ferramentas ao meu cinto de utilidades.
Posted in Dev, Python and tagged , , , , , .