Yield em python

Ao trabalharmos com volumes grandes de dados em listas, tuplas e dicionários, esbarramos no problema da performance. Manter todos esses dados em memória se torna custoso.

Diminuiremos bastante o uso de memória com os generators. A entrega de valores sobre demanda torna o uso de listas mais “barato".

Para ficar mais claro qual é o papel do yield, temos que entender alguns pontos chaves ao se trabalhar com listas e CIA em python.


Iterables

Todo objeto que pode ser percorrido com o uso de uma instrução assim:

 >>> for elemento in iterable:

           print elemento

Existem muitas formas de criar iterables em python:

 lista = ['a', 'b', 'f', 'c', 1, 2, 4] #criando um iterable

 string = "Uma string também pode ser iterada."

Em resumo todo objeto que implementa internamente o método mágico “iter" é um iterable, com exceção da string que para isso usa o método mágico “getitem".

Podemos verificar se um dado objeto é um iterable, utilizando o método
iter

:

 >>> iter([1,2,3])

O método retornará o próprio objeto, caso o mesmo seja um iterável ou um
TypeError exception
será levantado.

A vantagem dos iterables é podermos acessar seus valores a qualquer momento e quantas vezes desejarmos. A desvantagem disso é o espaço que eles ocupam em memória, com grandes volumes de dados isso pode ser um fator complicado.

Generators

Generators são um tipo de iterables, mas o custo em memória é bem menor. Os valores de um generator são lidos quando necessários e serão acessíveis somente uma vez.

Concluímos que iterables possuem
eagers evaluation
e generators possuem
lazy evaluation
.

Ao percorrermos o valor de um generator, estamos destruindo sua referência, o que nos impede de percorre-lo novamente. Tentar acessar um generator que não existe em memória vai levantar o erro

StopIteration

.

 >>> gerador

=

(letra

for

letra

in

"diofeher"

)

 >>> gerador.

next

()

 'd'

 >>> gerador.

next

()

 'i'

 >>>

for

letra

in

gerador:

 ...

print

letra

 ...

 o

 f

 e

 h

 e

 r

 >>> gerador.

next

()

 Traceback (most recent call last):

File

"", line

1

,

in

 StopIteration

Yield

Ficou bem mais simples entendermos o que o Yield faz. Na verdade, ele permite que retornemos um generator. Vamos ao exemplo.

 >>> def metodo_a():

                for x in [1, 2, 3, 4, 5, 6]

                     yield x

Nesse exemplo, estamos retornando um generator a quem chamar o nosso método. Podemos acessar o método next() e recebermos o próximo número na sequência, até que nosso generator não exista mais.

confira:

 >>> b  = metodo_a()

 >>> b.next()

 1

 >>> b.next()

 2

 ...

 >>> b.next()

 6

 >>> b.next()



 Traceback (most recent call last):

 File "<stdin>", line 1, in <module>

 StopIteration

 >>> b = metodo_a()

 >>> iter(b)

O exemplo deixa claro que o objeto
b

é do tipo generator, sendo assim podemos iterar.

Em caso de duvidas ou sugestões, deixe o seu comentário.

Referência