Sigueme en Twitter
«Anterior | Siguiente»

Sustitución de cadenas vs concatenación en Python

21/05/2009

Tenía la idea de que la sustitución de valores era más rápida que simplemente concatenar cadenas. Pero en Python tal parece que es al revés.

Probando con un caso -muy muy muy- extremo, de 1 millón de iteraciones tenemos resultados interesantes.

1
2
3
4
5
6
STRING1 = 'Esta es la '
STRING2 = 'iteracion numero: '
FINAL = ''
 
for i in xrange(0, 1000000):
	FINAL += STRING1 + STRING2 + str(i) + '\n'

Concatenando de esta manera el resultado de time es:

real	0m1.479s
user	0m1.396s
sys	0m0.081s

Y al cambiar casi todas las concatenaciones por sustituciones de esta manera:

5
6
for i in xrange(0, 1000000):
	FINAL += '%s%s %d\n' % (STRING1, STRING2, i)

Obtenemos estos tiempos:

real	0m1.830s
user	0m1.746s
sys	0m0.081s

Aquí la diferencia no es realmente significativa si tomamos en cuenta el enorme tamaño del bucle. Así que yo sigo prefiriendo no sacrificar la legibilidad del código y seguir utilizando sustituciones en lugar de concatenaciones.

Pero ojo, esto no es una sustitución completa. Si eliminamos la única concatenación que dejamos en el segundo código:

5
6
for i in xrange(0, 10000):
	FINAL = '%s %s%s %d\n' % (FINAL, STRING1, STRING2, i)

Con “apenas” 10,000 iteraciones, vamos a tener tiempos arriba de 2 segundos. Ya imaginarás como sube exponencialmente si aumentamos el rango. No se cual sea la razón, pero parece que no es buena idea sustituir miles de cadenas enormes.

real	0m2.043s
user	0m0.899s
sys	0m1.139s

Esta claro, si para ti es crítico el rendimiento; concatena, sino no hay problema con que utilices sustituciones.


Hay 5 comentarios:

  1. 22/05/2009zodman dice:
    for i in xrange(0, 10000):
    	FINAL = '%s %s%s %d\n' % (FINAL, STRING1, STRING2, i)

    Segun “entiendo yo” la variables FINAL se localiza en espacio de memoria y si la vuelves a asignar tiene que separar un espacio de memoria mas grande para asignar el nuevo FINAL

    FINAL += '%s%s %d\n' % (STRING1, STRING2, i)

    Con esto veo que FINAL no tiene que hasta cierto punto a redifinirse en memoria si no mas bien contatenarse. el espacio de memoria ya esta definido mas lo que le hace falta contatenar.

    Segun yo asi chambea esta cosa ……. pero python a bajo nivel de seleccion de memoria no se a ciencia cierta.

  2. 22/05/2009kad dice:

    Estas comparando peras con manzanas… o no, mas bien estas comparando el peso de manzanas con corazón y manzanas sin corazón. Me explico: en el primer ejemplo de concatenación estas declarando una sola vez a la variable FINAL, y solo le estas concatenando lo demás (para verlo, solo imprime la variable FINAL despues de los ciclos en ambos casos). La diferencia es que la variable FINAL esta siendo reescrita en el segundo caso, entonces python esta haciendo: borrar variable FINAL + crear espacio para variable FINAL + asignar valor para variable FINAL (a grosso modo, tampoco no se mucho de compiladores), mientras que en la concatenación que usas solamente hace 1 operación: concatenar. Cambia el primer ejemplo, quitale el += del principio y verás que los tiempos se acercan bastante uno y otro (creo que la concatenación sigue estando 1 o 2 centésimas de segundo más rápida).

    Otra cosa, el método de sustitución y el de concatenación son intrínsicamente distintos: la sustitución carga primero la cadena, luego busca los placeholders y luego los reemplaza, mientras que la concatenación simplemente los va agregando sin saber que son (de ahi que tengas que hacer un str(i) antes de concatenar, te daria un error de runtime de otra manera, creo)

    Creo que despues de todo si estabas comparando manzanas con peras, porque los mecanismos son diferentes.

  3. 22/05/2009kad dice:
    1
    2
    3
    4
    5
    6
    7
    8
    
    s1 = 'Esta es la'
    s2 = 'iteracion #'
    final = ''
     
    for i in xrange(0, 1000000):
      final = s1 + ' ' + s2 + str(i)
      #final = "%s %s%s" % (s1, s2, str(i))
    print final
  4. 22/05/2009pablasso dice:

    Muy cierto, a pesar de que los estoy comparando para lograr el mismo objetivo, trabajan de forma muy diferente. Gracias por la explicación.

  5. 22/05/2009izaac dice:

    Si sobre todo como lo menciona kad el string formatting necesita hacer algunas comprobaciones antes de incluir el valor de la variable en la cadena, aunque los placeholders no se incluyen hasta python 2.6+, versiones anteriores si necesitan comprobar si hay mapping keys, conversion flags, etc y luego realizar alguna conversión de ser necesario.

    La concatenación en cambio solo llega a a utilizar algunos métodos como __add__, __radd__, __str__, __unicode__

    Pero vaya! muy bien que vayas interesandote en las entrañas de Python.

Escribe tu comentario:

¿Escribiste código? [+]

Para hacerlo más legible puedes utilizar la etiqueta <pre>.
Ejemplo: <pre lang="php" line="1"> código </pre>
  • El atributo lang indica el lenguaje de programación.
  • El atributo line indica desde donde comienza la numeración.


  Los mas frikis pueden suscribirse a los comentarios por RSS.