Volver a la lista

Inmutabilidad de cadenas y reasignación de memoria

Aprenda por qué las cadenas son inmutables en Python, cómo funcionan en la memoria y qué impacto tiene esto en el rendimiento.

Intermedio
|
10min
|
Verificado (2026-07)
inmutabilidad de cadenasimmutableasignación de memoriainternadofunción id
Progreso0/18 (0%)

Inmutabilidad de las cadenas y reasignación de memoria

Al finalizar este tema

Comprenderás por qué las cadenas en Python son inmutables, cómo funcionan las operaciones de cadenas en la memoria y cómo evitar problemas de rendimiento al procesar grandes volúmenes de cadenas.


Las cadenas son inmutables

python
name = "Hello"
name[0] = "h"
# TypeError: 'str' object does not support item assignment

Las cadenas de Python son objetos inmutables. Una vez creadas, su contenido no se puede modificar. Todas las operaciones que parecen una "modificación" en realidad generan una nueva cadena.

python
name = "Hello"
print(id(name)) # 4385123456
name = name.lower()
print(id(name)) # 4385123520 ← ¡objeto diferente!

id() devuelve la dirección de memoria del objeto. Dado que el id cambió después de lower(), se creó una nueva cadena en lugar de modificar la existente.


Mutable vs. Inmutable

TipoModificableEjemplo
strInmutable"hello"
tupleInmutable(1, 2, 3)
intInmutable42
floatInmutable3.14
listMutable[1, 2, 3]
dictMutable{"a": 1}
setMutable{1, 2, 3}
python
# Listas: mutables — el contenido se puede modificar directamente
items = [1, 2, 3]
items[0] = 99
print(items) # [99, 2, 3] — mismo objeto, solo cambia el contenido
# Cadenas: inmutables — no se pueden modificar, se crea un nuevo objeto
text = "hello"
new_text = text.replace("h", "H")
print(text) # "hello" — original intacto
print(new_text) # "Hello" — nuevo objeto

¿Por qué se diseñó como inmutable?

1. Hashable — Puede usarse como clave de diccionario

python
# Las cadenas pueden usarse como claves de diccionario (porque son inmutables)
scores = {"alice": 90, "bob": 85}
# Las listas no pueden usarse como claves de diccionario (porque son mutables)
# scores = {[1, 2]: "value"} # TypeError: unhashable type: 'list'

Los diccionarios buscan datos mediante el valor hash de la clave. Si la clave cambia, el valor hash también cambia, lo que impide localizar los datos. Solo los objetos inmutables pueden ser hasheables.

2. Seguridad — se pueden compartir sin riesgo

python
def greet(name):
greeting = "Hello, " + name
return greeting
original = "World"
result = greet(original)
print(original) # "World" — la función no puede modificar original

Incluso si se pasa una cadena a una función, no hay que preocuparse de que el original cambie dentro de la función. Las listas pueden modificarse en su origen dentro de la función .append().

3. Seguridad de hilos

Cuando varios hilos leen la misma cadena simultáneamente, nadie puede modificarla, por lo que no se necesitan bloqueos (locks).


Internamiento de cadenas

Python reutiliza las cadenas que se usan con frecuencia. Esto se denomina internamiento (interning).

python
a = "hello"
b = "hello"
print(a is b) # True — ¡comparten el mismo objeto!
print(id(a) == id(b)) # True
c = "hello world!"
d = "hello world!"
print(c is d) # False o True — depende de la implementación

Las cadenas cortas y sencillas (en formato de identificador) se someten a interning. Aunque una cadena con el mismo contenido aparezca varias veces, solo existe una instancia en la memoria. Esto es posible porque son inmutables: al compartirlas, nadie puede modificarlas.

python
# is vs ==
a = "hello"
b = "hello"
print(a == b) # True — ¿los valores son iguales?
print(a is b) # True — ¿son el mismo objeto? (debido al interning)
# Para comparar cadenas, usa siempre ==. is es impredecible

Trampa de rendimiento: concatenación de cadenas

python
# Malo: concatenación de cadenas en un bucle — O(n²)
result = ""
for i in range(10000):
result += str(i) + "," # ¡Se crea una nueva cadena cada vez!

En cada iteración se crea una nueva cadena y se copia el contenido anterior. Al repetir el proceso 10 000 veces, se producen aproximadamente 50 millones de copias de caracteres (1 + 2 + 3 + ... + 10 000).

python
# Bueno: usar join — O(n)
result = ",".join(str(i) for i in range(10000))

join() calcula el tamaño final de antemano y asigna la memoria una sola vez. Esto reduce el número de copias a O(n).

Comparación de rendimiento

python
import time
# Método 1: += (lento)
start = time.time()
result = ""
for i in range(100000):
result += str(i)
print(f"+=: {time.time() - start:.3f}s")
# Método 2: join (rápido)
start = time.time()
result = "".join(str(i) for i in range(100000))
print(f"join: {time.time() - start:.3f}s")
# Método 3: io.StringIO (texto masivo)
import io
start = time.time()
buf = io.StringIO()
for i in range(100000):
buf.write(str(i))
result = buf.getvalue()
print(f"StringIO: {time.time() - start:.3f}s")
# Ejemplo de resultado:
# +=: 0.852s
# join: 0.031s (27 veces más rápido)
# StringIO: 0.029s

Patrones prácticos

Métodos para "modificar" cadenas de texto

python
text = "Hello, World!"
# Mayúsculas y minúsculas
text.upper() # "HELLO, WORLD!"
text.lower() # "hello, world!"
text.title() # "Hello, World!"
# Reemplazo
text.replace("World", "Python") # "Hello, Python!"
# Modificación por carácter (vía lista)
chars = list(text) # ['H', 'e', 'l', 'l', 'o', ...]
chars[0] = 'h'
result = "".join(chars) # "hello, World!"

Todos los métodos devuelven una nueva cadena. El original no cambia.

Combinación de f-strings

python
name = "Hoon"
age = 30
greeting = f"Hello, {name}! You are {age} years old."

Las f-strings crean la cadena final de una sola vez internamente. Esto es más eficiente y legible que realizar múltiples concatenaciones con +.


Comparación con otros lenguajes

java
// Java — String es inmutable, StringBuilder es mutable
String s = "Hello";
s = s + " World";  // Se crea un nuevo objeto String

StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");  // Modificación en el mismo objeto (mutable)
String result = sb.toString();
javascript
// JavaScript — Las cadenas son inmutables (igual que Python)
let s = "Hello";
s[0] = "h";      // No genera error, pero se ignora
console.log(s);  // "Hello" (sin cambios)
c
// C — El array de char es mutable
char s[] = "Hello";
s[0] = 'h';      // OK — cambia a "hello"

En la mayoría de los lenguajes modernos (Python, Java, JavaScript, Go, C#), las cadenas de texto son inmutables. Esta es una decisión de diseño común para garantizar la seguridad y la optimización. El StringBuilder de Java y el strings.Builder de Go cumplen la misma función que el join() o el io.StringIO de Python: siguen el patrón de ensamblar el contenido en un búfer mutable para luego crear la cadena inmutable final.


Resumen clave

ConceptoResumen
InmutableNo se puede modificar tras su creación. Toda "modificación" genera un nuevo objeto.
id()Comprobar la dirección de memoria de un objeto.
InterningLas cadenas idénticas se reutilizan en memoria (posible gracias a la inmutabilidad).
join()La forma correcta de concatenar cadenas. Usar += en bucles resulta en O(n²).
is vs ==is comprueba la identidad del objeto, mientras que == comprueba la igualdad de valores. Para cadenas, use ==.

La inmutabilidad de las cadenas es una decisión de diseño en Python. Sus beneficios —como poder usarse como claves de diccionarios, permitir el paso seguro de datos entre funciones y optimizar la memoria mediante el interning— compensan la restricción de no poder modificarse. Lo único que debe recordar en la práctica es: no acumule cadenas con += dentro de un bucle; use join() en su lugar.


💬 Preguntas y comentarios

0 comentarios

Puedes publicar sin iniciar sesión. Los comentarios de invitados no pueden editarse ni eliminarse después.

0/2000

Cargando...