¿Por qué es% s mejor que + para la concatenación?

88

Entiendo que deberíamos usar %spara concatenar una cadena en lugar de +en Python.

Podría hacer cualquiera de:

hello = "hello"
world = "world"

print hello + " " + world
print "%s %s" % (hello, world)
print "{} {}".format(hello, world)
print ' '.join([hello, world])

Pero, ¿por qué debería usar algo más que el +? Es más rápido escribir concatenación con un simple +. Luego, si observa la cadena de formato, especifique los tipos, por ejemplo, %sand %dy such. Entiendo que podría ser mejor ser explícito sobre el tipo.

Pero luego leí que el uso +para la concatenación debe evitarse aunque sea más fácil de escribir. ¿Existe una razón clara por la que las cadenas deben concatenarse de alguna de esas otras formas?

Niklas Rosencrantz
fuente
29
¿Quién te dijo que es mejor?
yannis
3
%sno es para concatenación, es una especificación de conversión para el formato de cadenas derivado de C's printf(3). Hay casos para usar eso o un operador de concatenación; que utilices debe basarse en el juicio de la situación, no en el dogma. Lo fácil que es escribir el código es completamente irrelevante porque solo lo vas a hacer una vez.
Blrfl
He reenfocado la pregunta solo a Python (aunque no soy una persona de Python y aún podría haber fallas en el código). Asegúrese de que esta es la pregunta que está haciendo, realice las actualizaciones apropiadas y considere hacer una pregunta diferente si está interesado en C o Java.
12
¡Y ahora tenemos las cuerdas f superiores ! print(f"{hello} {world}"), tiene legibilidad de concatenación ya que las variables se ven donde ocurren en la cadena y es más rápido que str.format.
Enrico Borba

Respuestas:

88
  1. Legibilidad. La sintaxis de la cadena de formato es más legible, ya que separa el estilo de los datos. Además, en Python, la %ssintaxis coaccionará automáticamente cualquier strtipo que no sea str; mientras que la concatenación solo funciona stry no se puede concatenar strcon int.

  2. Actuación. En Python stres inmutable, por lo que las cadenas izquierda y derecha deben copiarse en la nueva cadena para cada par de concatenación. Si concatena cuatro cadenas de longitud 10, estará copiando (10 + 10) + ((10 + 10) +10) + (((10 + 10) +10) +10) = 90 caracteres, en lugar de solo 40 caracteres. Y las cosas empeoran cuadráticamente a medida que aumenta el número y el tamaño de la cadena. Java optimiza este caso algunas veces transformando la serie de concatenación para usar StringBuilder, pero CPython no.

  3. Para algunos casos de uso, la biblioteca de registro proporciona una API que utiliza la cadena de formato para crear la cadena de entrada de registro de forma perezosa ( logging.info("blah: %s", 4)). Esto es excelente para mejorar el rendimiento si la biblioteca de registro decidió que la entrada de registro actual será descartada por un filtro de registro, por lo que no necesita formatear la cadena.

Lie Ryan
fuente
31
¿tiene alguna fuente científica o empírica para el n. ° 1? Porque yo creo que es mucho mucho menos legible (en especial con más de 2 o tres argumentos)
Lovis
44
@ L.Möller: no estoy muy seguro de qué tipo de fuente esperas de lo que en última instancia es una experiencia subjetiva (facilidad de lectura), pero si quieres mi razonamiento: 1)% s requiere 2 caracteres adicionales por marcador de posición vs + requiere mínimo de 4 (u 8 si sigue PEP8, 13 si coacciona), 2)% s está encerrado en una sola cadena, por lo que es más fácil analizar visualmente, con +, tiene más partes móviles: cadena cerrada, operador, variable , operador, cadena abierta, 3) la sintaxis para colorear% s tiene un color para cada función: cadena y marcador de posición, con + obtienes tres colores: cadena, operador y coloración variable.
Lie Ryan
44
@ L.Möller: 4) Tengo la opción de colocar cadenas de formato más largas en una variable o diccionario, lejos de donde se necesita formatear, 5) la cadena de formato puede ser especificada por el usuario desde un archivo de configuración, argumentos de comando o base de datos , lo mismo no se puede decir con concatenaciones. Pero sí, tampoco usaría% s cuando tengo más de 4-5 cosas para interpolar, en su lugar usaría la variante% (varname) s o "{foo}". Format () en Python. Creo que los nombres explícitos mejoran la legibilidad para cadenas de formato más largas con muchas variables interpoladas.
Lie Ryan
2
No sé qué es "cierto", por eso te pregunto si tienes evidencia :-). Realmente de acuerdo con su segundo comentario
Lovis
66
Me parece que el # 2 es sospechoso: ¿tiene pruebas documentadas? No estoy muy familiarizado con Java, pero en C # la concatenación es más rápida que la interpolación de cadenas . Estoy completamente de acuerdo con el n. ° 1 y realmente confío en eso para decidir cuándo usar qué, pero debes recordar que la interpolación requiere una gran cantidad de análisis de cadenas y complejidad donde la concatenación no requiere nada de eso.
Jimmy Hoffa
48

¿Soy el único que lee de izquierda a derecha?

Para mí, usar %ses como escuchar a hablantes de alemán, donde tengo que esperar hasta el final de una oración muy larga para escuchar cuál es el verbo.

¿Cuál de estos es más claro a simple vista?

"your %s is in the %s" % (object, location)

o

"your " + object + " is in the " + location  
Mawg
fuente
17
Obviamente, esto es subjetivo, ya que encuentro que el primero es más legible y más fácil de escribir y editar. El segundo entremezcla el texto con un código que oscurece ambos y agrega ruido. Por ejemplo, es fácil equivocarse en los espacios en el segundo.
JacquesB
55
@JacquesB Realmente creo que tu cerebro está tan familiarizado con este formato que inmediatamente saltas a los corchetes y reemplazas las palabras al instante. Técnicamente no es una lectura de izquierda a derecha, pero está perfectamente bien. Creo que también lo hago, así que sí, es más fácil de leer 1 porque sé que tengo que lidiar con problemas estúpidos de espaciado antes y después de las citas en el segundo, y es muy lento trabajar con eso.
Nelson
3
Después de ndécadas, mi mente también funciona así ;-) Pero aún mantengo mi respuesta, la segunda es más clara y fácil de leer, por lo tanto, mantener. Y eso se hace más evidente cuanto más parámetros tenga. Al final, si es un espectáculo de un solo hombre, ve con lo que estás familiarizado y cómodo; si es un esfuerzo de equipo, imponga revisiones de consistencia y código; la gente puede acostumbrarse a cualquiera.
Mawg
44
El primero es mucho más legible para mí porque tiene menos "cruft" en el medio de la oración. Es más fácil para mi ojo mirar hacia el final que para mi cerebro analizar las comillas, espacios y ventajas adicionales. Por supuesto, ahora me gusta mucho más Python 3.6 cuerdas de formato: f"your {object} is in the {location}".
Dustin Wyatt
8
También me resulta aún más difícil leer y escribir cuando la variable necesita estar entre comillas. "your '" + object + "' is in the '" + location + "'"... Ni siquiera estoy seguro de haberlo entendido ahora mismo ...
Dustin Wyatt
12

Un ejemplo que aclara el argumento de legibilidad:

print 'id: ' + id + '; function: ' + function + '; method: ' + method + '; class: ' + class + ' -- total == ' + total

print 'id: %s; function: %s; method: %s; class: %s --total == %s' % \
   (id, function, method, class, total)

(Tenga en cuenta que el segundo ejemplo no solo es más legible sino que también es más fácil de editar, puede cambiar la plantilla en una línea y la lista de variables en otra)

Otro problema es que el código% s también se convierte a la cadena, de lo contrario, debe usar la llamada str (), que también es menos legible que un código% s.

Lluvioso
fuente
1
No estoy de acuerdo con su primera declaración, pero podemos estar de acuerdo en diferir, estaba a punto de publicar una respuesta en la línea de su segunda, así que
voté a favor
6

Usando +debería no ser evitado en general. En muchos casos es el enfoque correcto. Usar %so .join()solo es preferible en casos particulares, y generalmente es bastante obvio cuando son la mejor solución.

En su ejemplo, está concatenando tres cadenas juntas, y el ejemplo que usa +es claramente el más simple y más legible y, por lo tanto, el recomendado.

%so .format()son útiles si desea interpolar cadenas o valores en el medio de una cadena más grande. Ejemplo:

print "Hello %s, welcome to the computer!" % name

En este caso, usarlo %ses más legible ya que evita cortar la primera cadena en múltiples segmentos. Especialmente si está interpolando múltiples valores.

.join() es apropiado si tiene una secuencia de cadenas de tamaño variable y / o desea concatenar cadenas múltiples con el mismo separador.

JacquesB
fuente
2

Dado que el orden de las palabras puede cambiar en diferentes idiomas, el formulario con %ses imprescindible si desea admitir correctamente la traducción de cadenas en su software.

martjno
fuente