2012-05-10 14 views
87

Mientras que el perfil de una pieza de código Python (python 2.6 hasta 3.2), he descubierto que el método str para convertir un objeto (en mi caso un número entero) a una cadena es casi un orden de magnitud más lento que usando el formato de cadena.rendimiento str en Python

Aquí es el punto de referencia

>>> from timeit import Timer 
>>> Timer('str(100000)').timeit() 
0.3145311339386332 
>>> Timer('"%s"%100000').timeit() 
0.03803517023435887 

¿Alguien sabe por qué esto es así? ¿Me estoy perdiendo algo?

+2

Y qué tal '' {} '. Format (100000) ' – wim

+0

Esa es la más lenta pero también la más flexible. –

Respuesta

104

'%s' % 100000 se evalúa por el compilador y es equivalente a una constante en tiempo de ejecución.

>>> import dis 
>>> dis.dis(lambda: str(100000)) 
    8   0 LOAD_GLOBAL    0 (str) 
       3 LOAD_CONST    1 (100000) 
       6 CALL_FUNCTION   1 
       9 RETURN_VALUE   
>>> dis.dis(lambda: '%s' % 100000) 
    9   0 LOAD_CONST    3 ('100000') 
       3 RETURN_VALUE   

% con una expresión de tiempo de ejecución no es (significativamente) más rápido que str:

>>> Timer('str(x)', 'x=100').timeit() 
0.25641703605651855 
>>> Timer('"%s" % x', 'x=100').timeit() 
0.2169809341430664 

tenga en cuenta que str es todavía un poco más lento, como dijo @DietrichEpp, esto se debe a str implica operaciones de búsqueda y funciones de llamada de función, mientras que % se compila en un solo bytecode inmediato:

>>> dis.dis(lambda x: str(x)) 
    9   0 LOAD_GLOBAL    0 (str) 
       3 LOAD_FAST    0 (x) 
       6 CALL_FUNCTION   1 
       9 RETURN_VALUE   
>>> dis.dis(lambda x: '%s' % x) 
10   0 LOAD_CONST    1 ('%s') 
       3 LOAD_FAST    0 (x) 
       6 BINARY_MODULO  
       7 RETURN_VALUE   

Por supuesto, lo anterior es cierto para el sistema que probé (CPython 2.7); otras implementaciones pueden diferir.

+0

De hecho, esta parece la razón, yo solo probé y el formato de cadena es aproximadamente un 5% más rápido que 'str'. Gracias por responder. No hay razón para cambiar el código en todas partes :-) –

+2

Para más detalles: 'str' es un nombre que puede recuperarse a algo que no sea el tipo de cadena, pero el formato de cadena - es decir, el método' str .__ mod__' - no puede reemplazarse, permite al compilador hacer la optimización. El compilador no hace mucho en cuanto a la optimización, pero hace más de lo que piensas :) –

+4

... y la lección para aprender aquí es: ¡nunca uses literales en pruebas como estas! – UncleZeiv

14

Una razón que viene a la mente es el hecho de que str(100000) implica una búsqueda global, pero "%s"%100000 no lo hace. El str global debe buscarse en el ámbito global. Esto no da cuenta de la diferencia total:

>>> Timer('str(100000)').timeit() 
0.2941889762878418 
>>> Timer('x(100000)', 'x=str').timeit() 
0.24904918670654297 

Como señaló thg435,

>>> Timer('"%s"%100000',).timeit() 
0.034214019775390625 
>>> Timer('"%s"%x','x=100000').timeit() 
0.2940788269042969 
Cuestiones relacionadas