En Python, las cadenas (str) son objetos inmutables, lo que significa que una vez creadas, su contenido no se puede cambiar. Cualquier operación que modifique la cadena (por ejemplo, concatenación o sustitución de caracteres) crea un nuevo objeto de cadena. Esto asegura seguridad y previsibilidad en el trabajo, ya que no hay que preocuparse de que alguien cambie la cadena de manera implícita en otra parte del código.
s = 'Hola' s2 = s.replace('H', 'J') # s permanecerá 'Hola', y s2 será 'Jola'
A diferencia de las cadenas, las listas en Python son objetos mutables. Su contenido se puede cambiar en su lugar a través de la indexación o métodos, lo que a veces conduce a efectos implícitos si la misma lista se utiliza en diferentes lugares.
Desde un punto de vista de rendimiento: si se necesitan modificar grandes cadenas con frecuencia (por ejemplo, en un bucle), la mecánica de inmutabilidad puede causar una asignación excesiva de memoria y un rendimiento lento del código. En tales casos, se recomienda usar una lista para acumular fragmentos de la cadena y luego unirlos a través de ''.join().
Ejemplo:
# Mal (lento para grandes volúmenes de datos): s = '' for word in words: s += word # En cada paso se crea una nueva cadena # Bien: parts = [] for word in words: parts.append(word) s = ''.join(parts)
Pregunta: ¿Por qué el siguiente código "s += 'abc'" es más rápido que "s = s + 'abc'" para cadenas?
Respuesta: Estas preguntas se hacen para comprobar si la persona entiende que ambas operaciones son en realidad equivalentes para cadenas (s += 'abc' crea un nuevo objeto, al igual que s = s + 'abc') — así es el comportamiento de los tipos en Python. Para listas, el comportamiento es diferente, ya que list += [...] muta el objeto, mientras que list = list + [...] crea uno nuevo. Para cadenas, siempre es una nueva cadena.
s = 'hi' s += 'abc' # Nuevo objeto, la cadena original no se modifica def compare(s): a = s a += 'abc' # id(a) != id(s) <-- objetos diferentes en memoria
Historia
En un proyecto donde se requería el procesamiento de grandes registros (análisis de cadenas de cientos de megabytes), un desarrollador utilizó una concatenación naive de cadenas en un bucle. El resultado fue una enorme caída en el rendimiento y un rápido aumento en el consumo de memoria. Después de optimizar mediante lista y join(), el tiempo de ejecución se redujo 20 veces.
Historia
En un proyecto, al intentar "corregir" un carácter en una cadena por índice, el programador esperaba ver un cambio en la cadena original. Surgió un error TypeError: 'str' object does not support item assignment. Después de varias horas, el depurador tuvo que crear una nueva cadena utilizando slicing y reemplazar el carácter necesario.
Historia
Al pasar cadenas a una función para su "complemento" (por ejemplo, agregar un sufijo a cada elemento de una lista), uno de los desarrolladores esperaba que la cadena cambiara "en su lugar". El resultado fue que la función devolvía None (debido a la falta de return), y todas las cadenas permanecían originales.