Python

Problemas con listas mutables en Python: Cómo evitar efectos inesperados

Las listas en Python son estructuras de datos mutables, lo que significa que su contenido puede modificarse después de su creación. Esta característica las diferencia de las tuplas, que son inmutables y no permiten cambios una vez definidas. Mientras que la mutabilidad de las listas ofrece gran flexibilidad, también puede generar efectos inesperados si no se gestionan de forma adecuada. Problemas como modificaciones no deseadas, referencias compartidas y errores en las funciones que reciben listas como argumentos son comunes al trabajar con listas mutables.

En esta entrada, abordaremos algunos de los errores más frecuentes que pueden aparecer al trabajar con listas mutables en Python y explicaremos cómo evitarlos para lograr un código más robusto, predecible y fácil de mantener.

¿Qué son las listas mutables en Python?

En Python, los objetos pueden ser mutables o inmutables:

  • Mutables: Son aquellos cuyo contenido puede modificarse después de su creación. Ejemplos: listas, diccionarios, conjuntos.
  • Inmutables: Son aquellos cuyo contenido no puede modificarse después de su creación. Ejemplos: tuplas, cadenas de texto, números (enteros, flotantes).
mi_lista = [1, 2, 3]
mi_lista.append(4)  # Modificamos la lista original

print(mi_lista)
[1, 2, 3, 4]

Problemas comunes al trabajar con listas mutables

Aquí te mostramos algunos de los errores más comunes y cómo evitarlos para que tu código sea más seguro y fácil de mantener.

Modificación inesperada al asignar listas

En Python, cuando asignas una lista a otra variable, ambas referencias apuntan al mismo objeto en memoria. Es decir, hay una única lista en memoria con dos nombres. Esto puede llevar a modificaciones no deseadas si una de las listas es modificada.

lista_a = [1, 2, 3]
lista_b = lista_a  # Ambas variables apuntan a la misma lista

lista_b.append(4)  # Modificamos lista_b
print(lista_a)  # La lista_a también cambió
[1, 2, 3, 4]

Solución: Para evitar este comportamiento, utiliza métodos como copy() o deepcopy() para crear copias independientes de la lista:

lista_a = [1, 2, 3]
lista_b = lista_a.copy()  # Ahora lista_b es una copia independiente

lista_b.append(4)
print(lista_a)  # [1, 2, 3] (No se modifica)
print(lista_b)  # [1, 2, 3, 4]
[1, 2, 3]
[1, 2, 3, 4]

Si la lista contiene elementos mutables, como sublistas, es recomendable usar deepcopy():

import copy

lista_anidada = [[1, 2], [3, 4]]
copia_profunda = copy.deepcopy(lista_anidada)

Mutabilidad en funciones: Modificaciones no deseadas

Cuando pasamos una lista como argumento a una función, esta puede modificarse dentro de la función, lo cual puede producir efectos indeseados si no se toma precaución.

def agregar_elemento(lista):
    lista.append(100)  # Modifica la lista original


mi_lista = [1, 2, 3]
agregar_elemento(mi_lista)
print(mi_lista)  # Se modificó inesperadamente
[1, 2, 3, 100]

Solución: Para evitar este problema, haz una copia de la lista dentro de la función antes de modificarla:

def agregar_elemento(lista):
    lista_copia = lista.copy()  # Copia de la lista
    lista_copia.append(100)
    return lista_copia


mi_lista = [1, 2, 3]
nueva_lista = agregar_elemento(mi_lista)
print(mi_lista)     # No cambia
print(nueva_lista)  # Nueva lista con un elemento
[1, 2, 3]
[1, 2, 3, 100]

Problemas con valores predeterminados mutables en funciones

Una de las trampas más sutiles en Python ocurre cuando usas una lista mutable como valor predeterminado de un parámetro de función. En este caso, todas las llamadas sucesivas compartirán la misma lista.

def agregar_valor(valor, lista=[]):
    lista.append(valor)
    return lista


print(agregar_valor(1))  # [1]
print(agregar_valor(2))  # [1, 2] (Acumula valores inesperadamente)
print(agregar_valor(3))  # [1, 2, 3]
[1]
[1, 2]
[1, 2, 3]

Solución: Una forma de evitar este comportamiento es usar None como valor predeterminado y crear una nueva lista dentro de la función:

def agregar_valor(valor, lista=None):
    if lista is None:
        lista = []  # Se crea una nueva lista en cada llamada
    lista.append(valor)
    return lista


print(agregar_valor(1))  # [1]
print(agregar_valor(2))  # [2] (Ya no acumula valores inesperados)
[1]
[2]

Mutabilidad en estructuras anidadas

Si una lista mutable contiene otras listas, cambiar una sublista afectará todas las referencias a esa sublista. Este problema puede ser difícil de detectar si no se presta atención.

matriz = [[0] * 3] * 3  # Crea 3 referencias al mismo objeto
matriz[0][0] = 1

print(matriz) # Todas las filas cambiaron
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]

Solución: Usa comprensión de listas para crear copias independientes de cada sublista:

matriz = [[0] * 3 for _ in range(3)]  # Cada fila es una lista independiente
matriz[0][0] = 1

print(matriz)
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]

Conclusiones

Las listas mutables en Python son una herramienta poderosa y flexible, pero pueden llevar a errores difíciles de detectar si no se manejan adecuadamente. Siguiendo las buenas prácticas aquí descritas, puedes evitar problemas comunes como referencias compartidas, modificaciones no deseadas y errores complicados en funciones. Asegúrate de crear copias adecuadas cuando sea necesario y ten en cuenta la mutabilidad de las estructuras de datos para escribir un código más predecible y fácil de depurar.

Nota: La imagen de este artículo fue generada utilizando un modelo de inteligencia artificial.

¿Te ha parecido de utilidad el contenido?

Daniel Rodríguez

Share
Published by
Daniel Rodríguez

Recent Posts

Síndrome del objeto brillante en ciencia de datos: el error simétrico a los costes hundidos

Hace poco publiqué una entrada en la que trataba de un sesgo bien documentado: aferrarse…

4 días ago

De la Regresión Logística al Scorecard: La Transformación Matemática

En un entrada previa explicamos qué son el WOE y el IV y por qué…

6 días ago

Analytics Lane lanza la versión 1.1 del laboratorio con nuevas suites de CLV y Scoring

Seguimos evolucionando el laboratorio de Analytics Lane y hoy lanzamos la versión 1.1, disponible en:…

7 días ago

Interés compuesto: la fuerza que multiplica tu dinero (y los errores que la anulan)

“El interés compuesto es la octava maravilla del mundo. El que lo entiende lo gana…

2 semanas ago

Cómo comparar datos con barras en Matplotlib: agrupadas, apiladas y porcentuales

Tienes los datos de ventas de tres productos en dos años distintos y quieres saber…

2 semanas ago

Costes hundidos en ciencia de datos: cuándo mantener un modelo y cuándo migrar

Imagina la situación. Tu equipo lleva tres años con un modelo en producción. No es…

3 semanas ago

This website uses cookies.