87 votos

rendimiento str en python

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

Aquí está 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?

105voto

georg Puntos 52691

'%s' % 100000 es evaluado 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 un tiempo de ejecución de expresión no es (mucho) 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 todavía está un poco más lento, como @DietrichEpp dijo, esto es debido a que str implica la búsqueda y la llamada a la función de operaciones, mientras % compila en una sola inmediata bytecode:

>>> 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 he probado (CPython 2.7); otras implementaciones pueden variar.

14voto

Dietrich Epp Puntos 72865

Una de las razones que me 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 tiene que ser consultado en el ámbito global. Esto no tiene en cuenta la totalidad de la diferencia:

 >>> 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
 

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: