Vejamos então um exemplo simples. Vocês pretendem criar uma função que vos gere todos os números ímpares, por exemplo. Ou todos os números pares. Ou todos os números de Fibonacci, you name it.

Para começar digamos que queremos implementar um gerador de todos os números naturais: 1,2,3,4,.... Simples? Não tão simples assim.
Vejamos...
Que tal algo como
- Código: Seleccionar Todos
def count():
n = 1
return n
n = n +1
Más notícias!


Claro que podemos fazer
- Código: Seleccionar Todos
n = 1
while True:
print n
n = n + 1
que imprime todos os números naturais. E podíamos, em vez de imprimir, guardar os números numa lista, por exemplo. mas não era bem isto que pretendíamos. O que queríamos era uma função que sempre que se invocaase nos desse mais um número natural... ou um número ímpar... Algo que pudessemos usar na forma
for n in impares(100):
print n
Era cool não? Para isso precisamos de uma função com memória, ou seja voltando ao nosso exemplo,
- Código: Seleccionar Todos
def count():
n = 1
return n
n = n +1
que não recomeçasse sempre na primeira linha, mas sim na linha a seguir ao return. Ou seja, uma função que "retornasse" um objecto mas que na próxima chamada da função arrancasse a seguir ao return, com memória do estado da função antes de devolver o objecto...
Pois as boas notícias são que isso existe no Python! Chama-se um gerador e para criar um gerador, basta substituir "return" numa função pela keyword "yield". Ficaria assim o nosso gerador contador de números naturais:
- Código: Seleccionar Todos
def count():
n = 1
while True:
yield n
n += 1
Usa-se assim:
- Código: Seleccionar Todos
for n in count():
print n
Ora experimentem...
Claro que este é um contador infinito. Se quiserem um contador até um certo número, nmax, ficaria assim:
- Código: Seleccionar Todos
def count(nmax):
n = 1
while n < nmax:
yield n
n = n +1
Experimentem fazer, por exemplo
- Código: Seleccionar Todos
>>> list(count(10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
Fixe, né?
Mas ainda mais engraçado.
Se fizermos
- Código: Seleccionar Todos
c = count()
de cada vez que fizermos
- Código: Seleccionar Todos
c.next()
obtemos um número novo na cadeia de números naturais.
- Código: Seleccionar Todos
>>> def count():
n = 1
while True:
yield n
n += 1
>>> c = count()
>>> c.next()
1
>>> c.next()
2
>>> c.next()
3
>>>
E agora um gerador de números ímpares:
- Código: Seleccionar Todos
>>> def impares(nmax):
n = 1
while n < nmax:
yield n
n += 2
>>>
>>> for n in impares(20):
print n
1
3
5
7
9
11
13
15
17
19
>>>
E com isto podem fazer:
- Código: Seleccionar Todos
>>> sum(impares(1000))
250000
Genial, não?

Mas isto é apenas uma pequena amostra do que os geradores podem fazer...