¿Las listas por comprensión y las funciones funcionales son más rápidas que los "bucles for"?

Resuelto Ericson Willians asked hace 10 años • 8 respuestas

En términos de rendimiento en Python, ¿ una lista de comprensión o funciones como map()y más rápidas que un bucle for? ¿Por qué, técnicamente, se ejecutan a velocidad C , mientras que el bucle for se ejecuta a la velocidad de la máquina virtual Python ?filter()reduce()

Supongamos que en un juego que estoy desarrollando necesito dibujar mapas enormes y complejos usando bucles for. Esta pregunta sería definitivamente relevante, ya que si la comprensión de una 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).

Ericson Willians avatar Mar 01 '14 07:03 Ericson Willians
Aceptado

Las siguientes son pautas aproximadas y conjeturas fundamentadas basadas en la experiencia. Debería timeito perfilar su caso de uso concreto para obtener cifras concretas, y esas cifras pueden ocasionalmente no estar de acuerdo con lo siguiente.

La comprensión de una lista suele ser un poquito más rápida que el forbucle exactamente equivalente (que en realidad crea una lista), probablemente porque no tiene que buscar la lista y su appendmétodo en cada iteración. Sin embargo, una lista por comprensión todavía realiza un bucle a 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 lista de comprensión en lugar de un bucle que no crea una lista, acumular sin sentido una lista de valores sin sentido y luego tirar la lista, suele ser más lento debido a la sobrecarga de crear y ampliar la lista. La comprensión de listas no es mágica y es inherentemente más rápida 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, no son necesariamente la opción más rápida. Se espera cierta aceleración si la función también está escrita en C. Pero en la mayoría de los casos que utilizan una lambda(u otra función de Python), la sobrecarga de configurar repetidamente marcos de pila de Python, etc., consume cualquier ahorro. Simplemente hacer el mismo trabajo en línea, sin llamadas a funciones (por ejemplo, una lista de comprensión en lugar de mapo filter) suele ser un poco más rápido.

Supongamos que en un juego que estoy desarrollando necesito dibujar mapas enormes y complejos usando bucles for. Esta pregunta sería definitivamente relevante, ya que si la comprensión de una 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 microoptimización a nivel de Python lo hará lo suficientemente rápido y deberías comenzar a pensar en pasar a C. Si bien es extenso Las microoptimizaciones a menudo pueden acelerar considerablemente el código Python; existe un límite bajo (en términos absolutos) para esto. Además, incluso antes de alcanzar ese techo, resulta simplemente más rentable (15% de aceleración frente a 300% de aceleración con el mismo esfuerzo) hacer el esfuerzo y escribir algo de C.

 avatar Mar 01 '2014 00:03

Si consulta la información en python.org , puede ver este resumen:

Version Time (seconds)
Basic loop 3.47
Eliminate dots 2.45
Local variable & no dots 1.79
Using map function 0.54

Pero realmente deberías leer el artículo anterior en detalle para comprender la causa de la diferencia de rendimiento.

También le sugiero encarecidamente que programe su código utilizando timeit . Al final del día, puede haber una situación en la que, por ejemplo, sea necesario salir del forbucle cuando se cumple una condición. Potencialmente, podría ser más rápido que averiguar el resultado llamando map.

Anthony Kong avatar Mar 01 '2014 00:03 Anthony Kong