Mutabilidad define si se puede cambiar un objeto sin cambiar su identificador (su dirección en la memoria):
Influencia en las funciones:
Ejemplo:
def f(lst): lst.append(42) data = [] f(data) print(data) # [42] def f2(x): x += 1 n = 1 f2(n) print(n) # 1
"¿Qué imprimirá el siguiente código?"
def foo(bar=[]): bar.append(1) return bar print(foo()) print(foo())
Respuesta: Imprimirá:
[1]
[1, 1]
Esto se debe a que los argumentos de la función se inicializan una vez al definirla, no en cada llamada. Listas (y otros objetos mutables) en los argumentos de las funciones son una trampa común.
Historia
En la API REST devolvían una lista a través de una función con un parámetro por defecto:
def get_default_items(items=[]): items.append('x') return items
Después de varias llamadas, se descubrió que la lista crecía, aunque se esperaba obtener solo un elemento.
Historia
En la función se planeaba "reemplazar" una cadena:
def replace_word(word): word.replace('a', 'b') word = 'data' replace_word(word) print(word) # Se esperaba 'dbtb', se obtuvo 'data'
Los métodos str no modifican la cadena original, sino que devuelven una nueva, pero se ignoró el valor del resultado devuelto.
Historia
Al trabajar con estructuras anidadas:
original = [[1, 2], [3, 4]] copy = original[:] copy[0][0] = -1 print(original) # [[-1, 2], [3, 4]]
Se utilizó una copia superficial, creyendo que solo se había modificado la copia, pero los objetos anidados permanecieron compartidos.