has - ¿Qué tan lenta es la concatenación de cadenas de Python vs. str.join?
list to string python (5)
De: Concatenación de cadenas eficiente
Método 1:
def method1():
out_str = ''''
for num in xrange(loop_count):
out_str += ''num''
return out_str
Método 4:
def method4():
str_list = []
for num in xrange(loop_count):
str_list.append(''num'')
return ''''.join(str_list)
Ahora me doy cuenta de que no son estrictamente representativos, y el cuarto método se agrega a una lista antes de recorrer y unir cada elemento, pero es una buena indicación.
La unión de cadenas es significativamente más rápida que la concatenación.
¿Por qué? Las cadenas son inmutables y no pueden cambiarse en su lugar. Para modificar uno, se necesita crear una nueva representación (una concatenación de los dos).
Como resultado de los comentarios en mi respuesta sobre este hilo , quería saber cuál es la diferencia de velocidad entre el operador +=
y ''''.join()
Entonces, ¿cuál es la comparación de velocidad entre los dos?
Esto es lo que los programas tontos están diseñados para probar :)
Use más
import time
if __name__ == ''__main__'':
start = time.clock()
for x in range (1, 10000000):
dog = "a" + "b"
end = time.clock()
print "Time to run Plusser = ", end - start, "seconds"
Salida de:
Time to run Plusser = 1.16350010965 seconds
Ahora con join ....
import time
if __name__ == ''__main__'':
start = time.clock()
for x in range (1, 10000000):
dog = "a".join("b")
end = time.clock()
print "Time to run Joiner = ", end - start, "seconds"
Salida de:
Time to run Joiner = 21.3877386651 seconds
Entonces en Python 2.6 en Windows, yo diría que + es aproximadamente 18 veces más rápido que unirse :)
Las respuestas existentes están muy bien escritas e investigadas, pero aquí hay otra respuesta para la era de Python 3.6, ya que ahora tenemos una interpolación literal de cadenas (AKA, f
-strings):
>>> import timeit
>>> timeit.timeit(''f/'{"a"}{"b"}{"c"}/''', number=1000000)
0.14618930302094668
>>> timeit.timeit(''"".join(["a", "b", "c"])'', number=1000000)
0.23334730707574636
>>> timeit.timeit(''a = "a"; a += "b"; a += "c"'', number=1000000)
0.14985873899422586
Prueba realizada con CPython 3.6.5 en una Retina MacBook Pro 2012 con Intel Core i7 a 2.3 GHz.
Esto de ninguna manera es un punto de referencia formal, pero parece que usar f
-strings es más o menos tan eficiente como usar +=
concatenación; cualquier métrica o sugerencia mejorada es, por supuesto, bienvenida.
Mi código original era incorrecto, parece que +
concatenación suele ser más rápido (especialmente con las versiones más nuevas de Python en hardware más nuevo)
Los tiempos son los siguientes:
Iterations: 1,000,000
Python 3.3 en Windows 7, Core i7
String of len: 1 took: 0.5710 0.2880 seconds
String of len: 4 took: 0.9480 0.5830 seconds
String of len: 6 took: 1.2770 0.8130 seconds
String of len: 12 took: 2.0610 1.5930 seconds
String of len: 80 took: 10.5140 37.8590 seconds
String of len: 222 took: 27.3400 134.7440 seconds
String of len: 443 took: 52.9640 170.6440 seconds
Python 2.7 en Windows 7, Core i7
String of len: 1 took: 0.7190 0.4960 seconds
String of len: 4 took: 1.0660 0.6920 seconds
String of len: 6 took: 1.3300 0.8560 seconds
String of len: 12 took: 1.9980 1.5330 seconds
String of len: 80 took: 9.0520 25.7190 seconds
String of len: 222 took: 23.1620 71.3620 seconds
String of len: 443 took: 44.3620 117.1510 seconds
En Linux Mint, Python 2.7, algunos procesadores más lentos
String of len: 1 took: 1.8840 1.2990 seconds
String of len: 4 took: 2.8394 1.9663 seconds
String of len: 6 took: 3.5177 2.4162 seconds
String of len: 12 took: 5.5456 4.1695 seconds
String of len: 80 took: 27.8813 19.2180 seconds
String of len: 222 took: 69.5679 55.7790 seconds
String of len: 443 took: 135.6101 153.8212 seconds
Y aquí está el código:
from __future__ import print_function
import time
def strcat(string):
newstr = ''''
for char in string:
newstr += char
return newstr
def listcat(string):
chars = []
for char in string:
chars.append(char)
return ''''.join(chars)
def test(fn, times, *args):
start = time.time()
for x in range(times):
fn(*args)
return "{:>10.4f}".format(time.time() - start)
def testall():
strings = [''a'', ''long'', ''longer'', ''a bit longer'',
''''''adjkrsn widn fskejwoskemwkoskdfisdfasdfjiz oijewf sdkjjka dsf sdk siasjk dfwijs'''''',
''''''this is a really long string that''s so long
it had to be triple quoted and contains lots of
superflous characters for kicks and gigles
@!#(*_#)(*$(*!#@&)(*E/xc4/x32/xff/x92/x23/xDF/xDFk^%#$!)%#^(*#'''''',
''''''I needed another long string but this one won''t have any new lines or crazy characters in it, I''m just going to type normal characters that I would usually write blah blah blah blah this is some more text hey cool what''s crazy is that it looks that the str += is really close to the O(n^2) worst case performance, but it looks more like the other method increases in a perhaps linear scale? I don''t know but I think this is enough text I hope.'''''']
for string in strings:
print("String of len:", len(string), "took:", test(listcat, 1000000, string), test(strcat, 1000000, string), "seconds")
testall()
Reescribí la última respuesta, ¿podrías compartir tu opinión sobre la forma en que probé?
import time
start1 = time.clock()
for x in range (10000000):
dog1 = '' and ''.join([''spam'', ''eggs'', ''spam'', ''spam'', ''eggs'', ''spam'',''spam'', ''eggs'', ''spam'', ''spam'', ''eggs'', ''spam''])
end1 = time.clock()
print("Time to run Joiner = ", end1 - start1, "seconds")
start2 = time.clock()
for x in range (10000000):
dog2 = ''spam''+'' and ''+''eggs''+'' and ''+''spam''+'' and ''+''spam''+'' and ''+''eggs''+'' and ''+''spam''+'' and ''+''spam''+'' and ''+''eggs''+'' and ''+''spam''+'' and ''+''spam''+'' and ''+''eggs''+'' and ''+''spam''
end2 = time.clock()
print("Time to run + = ", end2 - start2, "seconds")
NOTA: Este ejemplo está escrito en Python 3.5, donde range () actúa como el anterior xrange ()
La salida que obtuve:
Time to run Joiner = 27.086106206103153 seconds
Time to run + = 69.79100515996426 seconds
Personalmente prefiero '''' .unirse ([]) a ''Plusser way'' porque es más limpio y legible.