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:
...
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