Oi Habr. Muitas vezes, ao trabalhar com seqüências, surge a questão de sua criação. Parece estar acostumado a usar
List Comprehensions , e nos livros eles gritam sobre o uso obrigatório da função de
mapa embutida.
Neste artigo, consideraremos essas abordagens para trabalhar com sequências, comparar desempenho e também determinar em quais situações qual abordagem é melhor.
Compreensão da lista
A inclusão de lista é um mecanismo de geração de lista incorporado ao Python. Ele tem apenas uma tarefa - criar uma lista. A inclusão de lista cria uma lista de qualquer tipo iterável, transformando (filtrando) os valores recebidos.
Um exemplo de inclusão de lista simples para gerar uma lista de quadrados de números de 0 a 9:
squares = [x*x for x in range(10)]
Resultado:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
mapa
map é uma função incorporada ao idioma. Ele aceita uma função como o primeiro parâmetro e um objeto iterável como o segundo. Retorna um gerador (Python 3.x) ou uma lista (Python 2.x). Vou escolher o Python 3.
Um exemplo de chamada à função map para gerar uma lista de quadrados de números de 0 a 9:
squares = list(map(lambda x: x*x, range(10)))
Resultado:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Comparação de desempenho
Construir sem funções
Como um experimento, consideraremos os quadrados dos números do intervalo de 0 a 9.999.999:
python -m timeit -r 10 "[x*x for x in range(10000000)]" python -m timeit -r 10 "list(map(lambda x: x*x, range(10000000)))"
Resultados:
1 loop, best of 10: 833 msec per loop 1 loop, best of 10: 1.22 sec per loop
Como você pode ver, o método de
Compreensão de lista funciona cerca de 32% mais rápido. Tendo desmontado, não é possível obter respostas completas, porque a função do mapa "parece esconder os detalhes de seu trabalho". Mas provavelmente isso se deve à chamada constante da função lambda, dentro da qual os cálculos quadrados já estão sendo feitos. No caso da compreensão da lista, precisamos apenas calcular o quadrado.
Construa com recursos
Para comparação, também consideraremos os quadrados dos números, mas os cálculos estarão agora dentro da função:
python -m timeit -r 10 -s "def pow2(x): return x*x" "[pow2(x) for x in range(10000000)]" python -m timeit -r 10 -s "def pow2(x): return x*x" "list(map(pow2, range(10000000)))"
Resultados:
1 loop, best of 10: 1.41 sec per loop 1 loop, best of 10: 1.21 sec per loop
Desta vez, a situação é invertida. O método do
mapa foi 14% mais rápido. Neste exemplo, os dois métodos estão na mesma situação. Ambos devem chamar uma função para calcular o quadrado. No entanto, as otimizações internas da função de mapa permitem mostrar melhores resultados.
O que escolher?
Abaixo está a regra para escolher o método certo:

Pode haver exceções a essa regra, mas na maioria dos casos ela ajudará você a fazer a escolha certa!
o mapa é "mais seguro"?
Por que muitos pedem o uso do
mapa . O fato é que, em alguns casos, o mapa é realmente mais seguro do que a compreensão da lista.
Por exemplo:
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = [x*x for x in values]
A saída do programa será a seguinte:
a 3 b 3 c 3
Agora reescreva o mesmo código usando o
mapa :
symbols = ['a', 'b', 'c'] values = [1, 2, 3] for x in symbols: print(x) squared = map(lambda x: x*x, values)
Conclusão:
a a b b c c
O mais observador já percebeu pela sintaxe do uso do
mapa que este é o Python 2. De fato, no segundo python, havia um tipo semelhante de problema com a substituição de variáveis. No entanto, no Python 3, esse problema foi corrigido e não é mais relevante.
Os exemplos descritos acima mostrarão os mesmos resultados. Também pode parecer que este é um erro estúpido e você nunca cometerá esse erro; no entanto, isso pode acontecer quando você simplesmente transferiu um bloco de código com um loop interno de outro bloco. Tal erro pode gastar muito tempo e nervos para consertá-lo.
Conclusão
A comparação mostrou que cada um dos métodos é bom em sua situação.
- Se você não precisar de todos os valores calculados de uma só vez (ou talvez eles não sejam necessários), você deve optar pelo mapa . Portanto, conforme necessário, você solicitará uma parte dos dados do gerador, economizando uma grande quantidade de memória (Python 3. No Python 2, isso não faz sentido, pois o mapa retorna uma lista).
- Se você precisar calcular todos os valores de uma só vez e os cálculos puderem ser feitos sem o uso de funções, faça uma escolha na direção de Compreensão da lista . Como mostrado pelos resultados de experimentos - ele tem uma vantagem significativa no desempenho.
PS: Se eu perdi alguma coisa, fico feliz em discutir isso com você nos comentários.