Las siguientes son pautas aproximadas y conjeturas educadas basadas en la experiencia. Debería timeit
o perfilar su caso de uso concreto para obtener números concretos, y esos números pueden estar ocasionalmente en desacuerdo con los siguientes.
La comprensión de una lista suele ser un poco más rápida que el for
bucle precisamente equivalente (que en realidad construye una lista), muy probablemente porque no tiene que buscar la lista y su append
método en cada iteración. Sin embargo, una comprensión de la lista todavía hace un bucle de nivel de código de bytes:
>>> dis.dis(<the code object for `[x for x in range(10)]`>)
1 0 BUILD_LIST 0
3 LOAD_FAST 0 (.0)
>> 6 FOR_ITER 12 (to 21)
9 STORE_FAST 1 (x)
12 LOAD_FAST 1 (x)
15 LIST_APPEND 2
18 JUMP_ABSOLUTE 6
>> 21 RETURN_VALUE
Usar una comprensión de la lista en lugar de un bucle que no construye una lista, acumular sin sentido una lista de valores sin sentido y luego tirar la lista, a menudo es más lento debido a la sobrecarga de crear y extender la lista. Las comprensiones de listas no son mágicas, es inherentemente más rápido que un buen bucle antiguo.
En cuanto a las funciones de procesamiento de listas funcionales: si bien están escritas en C y probablemente superan a las funciones equivalentes escritas en Python, son no necesariamente la opción más rápida. Se espera algo de velocidad si la función también está escrita en C. Pero la mayoría de los casos que usan una lambda
(u otra función de Python), la sobrecarga de configurar repetidamente los marcos de pila de Python, etc., consume cualquier ahorro. Simplemente hacer el mismo trabajo en línea, sin llamadas a funciones (por ejemplo, una comprensión de la lista en lugar de map
o filter
) es a menudo un poco más rápido.
Supongamos que en un juego que estoy desarrollando necesito dibujar mapas complejos y enormes usando bucles. Esta pregunta sería definitivamente relevante, ya que si una comprensión de la lista, por ejemplo, es realmente más rápida, sería una opción mucho mejor para evitar retrasos (a pesar de la complejidad visual del código).
Lo más probable es que si un código como este no es lo suficientemente rápido cuando se escribe en un buen Python no "optimizado", ninguna cantidad de micro optimización de nivel de Python lo hará lo suficientemente rápido y debe comenzar a pensar en caer a C. Las micro optimizaciones a menudo pueden acelerar el código de Python considerablemente, hay un límite bajo (en términos absolutos) para esto. Además, incluso antes de alcanzar ese techo, se vuelve simplemente más rentable (15% de aceleración frente a 300% de aceleración con el mismo esfuerzo) para morder la bala y escribir algo de C.
Usted pregunta específicamente sobre
map()
,filter()
yreduce()
, pero supongo que quiere saber sobre programación funcional en general. Habiendo probado esto yo mismo en el problema de calcular distancias entre todos los puntos dentro de un conjunto de puntos, la programación funcional (usando lastarmap
función delitertools
módulo incorporado ) resultó ser un poco más lenta que los bucles for (tomando 1.25 veces más, en hecho). Aquí está el código de muestra que utilicé:¿La versión funcional es más rápida que la versión de procedimiento?
fuente
Escribí un script simple que prueba la velocidad y esto es lo que descubrí. En realidad, el bucle fue más rápido en mi caso. Eso realmente me sorprendió, mira abajo (estaba calculando la suma de cuadrados).
fuente
int
desquare_sum4
también hace que sea un poco más rápido y un poco más lento que el bucle.Yo modifiqué @ código de Alisa y se utiliza
cProfile
para mostrar por qué lista por comprensión es más rápido:Aquí están los resultados:
EN MI HUMILDE OPINIÓN:
reduce
ymap
en general son bastante lentos. No solo eso, usandosum
en los iteradores quemap
regresó es lento, en comparación consum
con una listafor_loop
utiliza append, que por supuesto es lento hasta cierto puntosum
mucho más rápida, en contraste conmap
fuente
Agregando un giro a la respuesta de Alphii , en realidad el bucle for sería el segundo mejor y aproximadamente 6 veces más lento que
map
Los principales cambios han sido eliminar las
sum
llamadas lentas , así como las probablemente innecesariasint()
en el último caso. Poner el bucle y el mapa for en los mismos términos lo convierte en un hecho bastante real. Recuerde que las lambdas son conceptos funcionales y, en teoría, no deberían tener efectos secundarios, pero, bueno, pueden tener efectos secundarios como sumara
. Resultados en este caso con Python 3.6.1, Ubuntu 14.04, Intel (R) Core (TM) i7-4770 CPU @ 3.40GHzfuente
Logré modificar algunos de los códigos de @ alpiii y descubrí que la comprensión de la Lista es un poco más rápida que para el bucle. Puede ser causado por
int()
, no es justo entre la comprensión de la lista y el bucle for.fuente