Esse conceito não é novo e data dos anos 60's. Mas o termo comprehension foi usado pela primeira vez na linguagem NPL.
E as List Comprehension tem como origem as representação do conjuntos da matemática:
{x ∈ N | 0 < x < 7}
Lê-se: x pertence ao conjunto dos Naturais, tal que 0 é menor que x e x menor que 7. O que restringiria esse conjunto a {1, 2, 3, 4, 5, 6}.Em Python, uma List comprehension tem a seguinte sintaxe:
[x * 2 for x in lista]Nesse exemplo abaixo, multiplicamos os itens da lista por 2, atribuimos à variável nova_lista:
>>> lista = [1, 2, 3, 4, 5] >>> nova_lista = [x * 2 for x in lista] >>> nova_lista [2, 4, 6, 8, 10]Sendo que o 'x * 2' é executado em cada item da lista. Um código mais limpo e intuitivo do que uma versão usando a builtin function map.
>>> def vezes_2(n): ... return n * 2 ... ... >>> map(vezes_2, range(6)) [0, 2, 4, 6, 8, 10]Poderiamos fazer essa operação com uma lambda function.
>>> map(lambda x: x * 2, range(6)) [0, 2, 4, 6, 8, 10]
Um código análogo sem List comprehension:
>>> lista = [1, 2, 3, 4, 5] >>> nova_lista = [] >>> for x in lista: ... nova_lista.append(x * 2) ... ... >>> >>> nova_lista [2, 4, 6, 8, 10]Dentro das List comprehensions ainda se pode usar condicionais, para filtrar elementos na criação das novas listas.
>>> frase = ['o', 'rato', 'roeu', 'a', 'roupa', 'do', 'rei', 'de', 'roma'] >>> [p for p in frase if p[0] == 'r'] ['rato', 'roeu', 'roupa', 'rei', 'roma']Aqui eu verifico se a primeira letra da palavra é 'r'.
Criei um pequeno script para comparar a performance das List comprehensions. Escrevi duas funções, uma usando List comprehensions e outra não, que criam uma lista com os números pares entre 0 e 1000000. Para fazer a comparação usei a biblioteca cProfile.
def foo(): l = [] for i in range(1000000): if i % 2 == 0: l.append(i) def foo_listcomp(): l = [i for i in range(1000000) if i % 2 == 0] cProfile.run('foo()') cProfile.run('foo_listcomp()')Executando o código.
O código convencional chega a ser 10 vezes mais lento que o código que utiliza List comprehension. 1.739 segundos contra 0.165.$ python bench.py 500004 function calls in 1.739 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.009 0.009 1.739 1.739 <string>:1(<module>) 1 0.936 0.936 1.730 1.730 bench.py:61(foo) 500000 0.769 0.000 0.769 0.000 {method 'append' of 'list'... 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof... 1 0.025 0.025 0.025 0.025 {range} 4 function calls in 0.165 seconds Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.015 0.015 0.165 0.165:1( ) 1 0.125 0.125 0.150 0.150 bench.py:67(foo_listcomp) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof... 1 0.024 0.024 0.024 0.024 {range}
A performance e a simplicidade do código justifica o uso das List comprehensions quando se quer criar listas a partir de listas, sua finalidade semântica. Mas quando a lógica envolvida na geração da nova lista é muito complexa, o seu uso pode diminuir a legibilidade do código drasticamente.
Referências:
Google Style Guide
Documentação Python
The History of Python
Nenhum comentário:
Postar um comentário