Python para Desenvolvedores

2ª edição, revisada e ampliada

Capítulo 15: Geradores


As funções geralmente seguem o fluxo convencional de processar, retornar valores e encerrar. Geradores funcionam de forma similar, porém lembram o estado do processamento entre as chamadas, permanecendo em memória e retornando o próximo item esperado quando ativados.

Os geradores apresentam várias vantagens em relação às funções convencionais:

  • Lazy Evaluation: geradores só são processados quando é realmente necessário, sendo assim, economizam recursos de processamento.
  • Reduzem a necessidade da criação de listas.
  • Permitem trabalhar com sequências ilimitadas de elementos.

Geradores geralmente são evocados através de um laço for. A sintaxe é semelhante a da função tradicional, só que a instrução yield substitui o return. A nova cada iteração, yield retorna o próximo valor.

Exemplo:

In [4]:
def gen_pares():
    """
    Gera números pares entre 0 e 20
    """
    i = 0

    while i <= 20:
        yield i
        i += 2

# Mostra cada número e passa para o próximo
for n in gen_pares():
    print n
0
2
4
6
8
10
12
14
16
18
20

Outro exemplo:

In [7]:
import os

# Encontra arquivos recursivamente
def find(path='.'):

    for item in os.listdir(path):
        fn = os.path.normpath(os.path.join(path, item))

        if os.path.isdir(fn):

            for f in find(fn):
                yield f

        else:
            yield fn

# A cada iteração, o gerador devolve
# um novo nome de arquivo
for fn in find():
    print fn
Capitulo15_Geradores.ipynb
libpeerconnection.log

Existem vários geradores que fazem parte da própria linguagem, como o builtin xrange(). Além disso, no módulo itertools, estão definidos vários geradores úteis.

Para converter a saída do gerador em uma lista:

lista = list(gerador())

Assim, todos os itens serão gerados de uma vez.

In [1]:
 
Out[1]: