Un antipatrón común en Python es concatenar una secuencia de cadenas usando +
un bucle. Esto es malo porque el intérprete de Python tiene que crear un nuevo objeto de cadena para cada iteración, y termina tomando tiempo cuadrático. (Las versiones recientes de CPython aparentemente pueden optimizar esto en algunos casos, pero otras implementaciones no pueden, por lo que se desalienta a los programadores a confiar en esto). ''.join
Es la forma correcta de hacerlo.
Sin embargo, he oído decir ( incluido aquí en Stack Overflow ) que nunca, nunca debes usar +
para la concatenación de cadenas, sino que siempre debes usar ''.join
o formatear una cadena. No entiendo por qué este es el caso si solo estás concatenando dos cadenas. Si mi interpretación es correcta, no debe tomar tiempo cuadrática, y creo que a + b
es más limpio y más fácil de leer que sea ''.join((a, b))
o '%s%s' % (a, b)
.
¿Es una buena práctica usar +
para concatenar dos cadenas? ¿O hay un problema que desconozco?
+
es más rápido o más lento? ¿Y por qué?In [2]: %timeit "a"*80 + "b"*80
1000000 loops, best of 3: 356 ns per loop
In [3]: %timeit "%s%s" % ("a"*80, "b"*80)
1000000 loops, best of 3: 907 ns per loop
In [3]: %timeit "%s%s" % (a, b) 1000000 loops, best of 3: 590 ns per loop
In [4]: %timeit a + b 10000000 loops, best of 3: 147 ns per loop
__str__
. Vea mi respuesta para ejemplos.Respuestas:
No hay nada de malo en concatenar dos cadenas con
+
. De hecho, es más fácil de leer que''.join([a, b])
.Sin embargo, tiene razón en que concatenar más de 2 cadenas
+
es una operación O (n ^ 2) (en comparación con O (n) parajoin
) y, por lo tanto, se vuelve ineficiente. Sin embargo, esto no tiene que ver con el uso de un bucle. Evena + b + c + ...
es O (n ^ 2), la razón es que cada concatenación produce una nueva cadena.CPython2.4 y superior intentan mitigar eso, pero aún es recomendable usarlo
join
cuando se concatenen más de 2 cadenas.fuente
.join
toma un iterable, por lo tanto.join([a,b])
y.join((a,b))
son válidas.+
o+=
en la respuesta aceptada (desde 2013) en stackoverflow.com/a/12171382/378826 (de Lennart Regebro) incluso para CPython 2.3+ y elegir el patrón "agregar / unir" si esto deja en claro idea para la solución del problema en cuestión.El operador Plus es una solución perfecta para concatenar dos cadenas de Python. Pero si sigue agregando más de dos cadenas (n> 25), es posible que desee pensar en otra cosa.
''.join([a, b, c])
El truco es una optimización del rendimiento.fuente
append()
incluir cadenas en una lista.n > 25
. Los humanos necesitan puntos de referencia para comenzar en alguna parte.La suposición de que uno nunca debe usar + para la concatenación de cadenas, sino que siempre debe usar '' .join puede ser un mito. Es cierto que el uso
+
crea copias temporales innecesarias de objetos de cadena inmutables, pero el otro hecho no mencionado es que llamarjoin
a un bucle generalmente agregaría la sobrecarga defunction call
. Tomemos tu ejemplo.Cree dos listas, una a partir de la pregunta SO vinculada y otra más grande fabricada
Vamos a crear dos funciones,
UseJoin
yUsePlus
usar las respectivasjoin
y+
funcionalidades.Vamos a correr el tiempo con la primera lista
Tienen casi el mismo tiempo de ejecución.
Vamos a usar cProfile
Y parece que el uso de Join da como resultado llamadas de función innecesarias que podrían aumentar la sobrecarga.
Ahora volviendo a la pregunta. ¿Se debe desalentar el uso de
+
overjoin
en todos los casos?Creo que no, las cosas deben tomarse en consideración
Y, por supuesto, en un desarrollo, la optimización prematura es malvada.
fuente
join
dentro del propio ciclo, sino que el ciclo generaría una secuencia que se pasaría para unirse.Cuando se trabaja con varias personas, a veces es difícil saber exactamente qué está sucediendo. El uso de una cadena de formato en lugar de concatenación puede evitar una molestia particular que nos ha sucedido muchas veces:
Digamos, una función requiere un argumento, y lo escribes esperando obtener una cadena:
Por lo tanto, esta función se puede usar con bastante frecuencia en todo el código. Es posible que sus compañeros de trabajo sepan exactamente lo que hace, pero no necesariamente estén completamente actualizados en lo interno, y pueden no saber que la función espera una cadena. Y entonces pueden terminar con esto:
No habría ningún problema si solo utilizara una cadena de formato:
Lo mismo es cierto para todos los tipos de objetos que definen
__str__
, que también pueden pasarse:Entonces sí: si puede usar una cadena de formato, hágalo y aproveche lo que Python tiene para ofrecer.
fuente
+
.zeta = u"a\xac\u1234\u20ac\U00008000"
por lo que tendría que usarprint 'bar: ' + unicode(zeta)
para asegurarse de que no se produzca un error.%s
lo hace bien sin tener que pensarlo, y es mucho más corto"bar: %s"
podrían traducirse a"zrb: %s br"
algún otro idioma. La%s
versión simplemente funcionará, pero la versión string-concat se convertiría en un desastre para manejar todos los casos y sus traductores ahora tendrían dos traducciones separadas para tratardef
.He hecho una prueba rápida:
y cronometrado:
Aparentemente hay una optimización para el
a = a + b
caso. No exhibe el tiempo O (n ^ 2) como se podría sospechar.Entonces, al menos en términos de rendimiento, el uso
+
está bien.fuente
De acuerdo con los documentos de Python, el uso de str.join () le dará consistencia de rendimiento en varias implementaciones de Python. Aunque CPython optimiza el comportamiento cuadrático de s = s + t, otras implementaciones de Python pueden no hacerlo.
Tipos de secuencia en documentos de Python (consulte la nota al pie [6])
fuente
Yo uso lo siguiente con Python 3.8
fuente
'' .join ([a, b]) es una mejor solución que + .
Porque el Código debe escribirse de manera que no perjudique a otras implementaciones de Python (PyPy, Jython, IronPython, Cython, Psyco y demás)
formar un + = b o a = a + b es frágil incluso en CPython y no está presente en absoluto en las implementaciones que no utilizan refcounting (recuento de referencias es una técnica de almacenar el número de referencias, indicadores, o las manijas a una recurso como un objeto, bloque de memoria, espacio en disco u otro recurso )
https://www.python.org/dev/peps/pep-0008/#programming-recommendations
fuente
a += b
funciona en todas las implementaciones de Python, es solo que en algunas de ellas toma tiempo cuadrático cuando se realiza dentro de un ciclo ; La pregunta era sobre la concatenación de cadenas fuera de un bucle.