Tópicos Relacionados a Geradores em Python

Beginner

This tutorial is from open-source community. Access the source code

Introdução

Esta seção introduz alguns tópicos adicionais relacionados a geradores, incluindo expressões geradoras e o módulo itertools.

Expressões Geradoras (Generator Expressions)

Uma versão geradora de uma compreensão de lista (list comprehension).

>>> a = [1,2,3,4]
>>> b = (2*x for x in a)
>>> b
<generator object at 0x58760>
>>> for i in b:
...   print(i, end=' ')
...
2 4 6 8
>>>

Diferenças em relação às Compreensões de Lista.

  • Não constrói uma lista.
  • Útil apenas para iteração.
  • Uma vez consumida, não pode ser reutilizada.

Sintaxe geral.

(<expressão> for i in s if <condicional>)

Também pode servir como um argumento de função.

sum(x*x for x in a)

Pode ser aplicado a qualquer iterável (iterable).

>>> a = [1,2,3,4]
>>> b = (x*x for x in a)
>>> c = (-x for x in b)
>>> for i in c:
...   print(i, end=' ')
...
-1 -4 -9 -16
>>>

O principal uso de expressões geradoras é em código que realiza algum cálculo em uma sequência, mas usa o resultado apenas uma vez. Por exemplo, remover todos os comentários de um arquivo.

f = open('somefile.txt')
lines = (line for line in f if not line.startswith('#'))
for line in lines:
    ...
f.close()

Com geradores, o código roda mais rápido e usa pouca memória. É como um filtro aplicado a um fluxo (stream).

Por que Geradores

  • Muitos problemas são expressos de forma muito mais clara em termos de iteração.
    • Iterar sobre uma coleção de itens e realizar algum tipo de operação (pesquisa, substituição, modificação, etc.).
    • Pipelines de processamento podem ser aplicados a uma ampla gama de problemas de processamento de dados.
  • Melhor eficiência de memória.
    • Produzem valores apenas quando necessário.
    • Contraste com a construção de listas gigantes.
    • Podem operar em dados de streaming.
  • Geradores incentivam a reutilização de código.
    • Separa a iteração do código que usa a iteração.
    • Você pode construir uma caixa de ferramentas de funções de iteração interessantes e misturar e combinar (mix-n-match).

Módulo itertools

O itertools é um módulo de biblioteca com várias funções projetadas para auxiliar com iteradores/geradores.

itertools.chain(s1,s2)
itertools.count(n)
itertools.cycle(s)
itertools.dropwhile(predicate, s)
itertools.groupby(s)
itertools.ifilter(predicate, s)
itertools.imap(function, s1, ... sN)
itertools.repeat(s, n)
itertools.tee(s, ncopies)
itertools.izip(s1, ... , sN)

Todas as funções processam dados iterativamente. Elas implementam vários tipos de padrões de iteração.

Mais informações no tutorial Generator Tricks for Systems Programmers da PyCon '08.

Nos exercícios anteriores, você escreveu algum código que acompanhava as linhas sendo escritas em um arquivo de log e as analisava em uma sequência de linhas. Este exercício continua a se basear nisso. Certifique-se de que o stocksim.py ainda está em execução.

Exercício 6.13: Expressões Geradoras

Expressões geradoras são uma versão geradora de uma compreensão de lista (list comprehension). Por exemplo:

>>> nums = [1, 2, 3, 4, 5]
>>> squares = (x*x for x in nums)
>>> squares
<generator object <genexpr> at 0x109207e60>
>>> for n in squares:
...     print(n)
...
1
4
9
16
25

Ao contrário de uma compreensão de lista, uma expressão geradora só pode ser usada uma vez. Portanto, se você tentar outro loop for, não obterá nada:

>>> for n in squares:
...     print(n)
...
>>>

Exercício 6.14: Expressões Geradoras em Argumentos de Função

Expressões geradoras são, às vezes, colocadas em argumentos de função. Parece um pouco estranho no início, mas tente este experimento:

>>> nums = [1,2,3,4,5]
>>> sum([x*x for x in nums])    ## A list comprehension
55
>>> sum(x*x for x in nums)      ## A generator expression
55
>>>

No exemplo acima, a segunda versão usando geradores usaria significativamente menos memória se uma lista grande estivesse sendo manipulada.

No seu arquivo portfolio.py, você realizou alguns cálculos envolvendo compreensões de lista. Tente substituí-los por expressões geradoras.

Exercício 6.15: Simplificação de código

Expressões geradoras são frequentemente uma substituição útil para pequenas funções geradoras. Por exemplo, em vez de escrever uma função como esta:

def filter_symbols(rows, names):
    for row in rows:
        if row['name'] in names:
            yield row

Você poderia escrever algo como isto:

rows = (row for row in rows if row['name'] in names)

Modifique o programa ticker.py para usar expressões geradoras conforme apropriado.

Resumo

Parabéns! Você concluiu o laboratório More Generators. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.