Tiza Las materias del CBC
Practicar →

Pensamiento Computacional (090) · Unidad 4 — Estructuras de datos

Mutabilidad y referencias

Con listas, b = a no copia nada: los dos nombres apuntan a la misma lista. Tocás una y cambia la otra.

Practicar este tema →7 ejercicios que te corrigen paso a paso · gratis, sin cuenta

La explicación

La sorpresa

a = [1, 2, 3]
b = a
b.append(4)
print(a)   →  [1, 2, 3, 4]

Tocamos b y cambió a. Con números esto no pasaba: en el tema 2.1, y = x copiaba el valor y las variables quedaban independientes.

Por qué

Una variable no contiene una lista: apunta a ella. b = a no crea una lista nueva, sólo agrega otro nombre para la misma. Como si una persona tuviera apodo: llamala como la llames, es la misma persona.

Con números no se nota porque son inmutables: no se pueden modificar en el lugar. Cuando hacés x = x + 1 no cambiás el 5, creás un 6 y apuntás ahí.

Cómo copiar de verdad

b = a.copy()     # copia
b = a[:]         # también (rebanada de todo)
b = list(a)      # también

Cualquiera de las tres crea una lista nueva. A partir de ahí son independientes.

Lo mismo pasa con las funciones

def agregar_cero(lista):
    lista.append(0)

mis_numeros = [1, 2]
agregar_cero(mis_numeros)
print(mis_numeros)   →  [1, 2, 0]

La función no devuelve nada, pero igual modificó la lista de afuera, porque recibió una referencia a la misma lista. Con un número esto no pasaría.

Esto no es un defecto, es una herramienta — pero hay que hacerlo a propósito. Si no querés tocar la original, copiá adentro de la función:
def agregar_cero(lista):
    nueva = lista.copy()
    nueva.append(0)
    return nueva

Modificar contra reasignar

b.append(4)   → modifica la lista compartida: a también cambia
b = [9, 9]    → apunta b a otra lista: a queda igual

La diferencia es si tocás la lista o si movés el nombre. Es la distinción clave del tema y la que más se pregunta.

Cómo preguntar si son la misma

a == b   → ¿tienen el mismo contenido?
a is b   → ¿son el mismo objeto?

Con b = a las dos preguntas dan True. Con c = a.copy(), en cambio, a == c da True y a is c da False: mismo contenido, dos listas distintas. Ese is es la forma rápida de verificar en la consola si una copia se copió de verdad.

El parámetro por defecto que se acuerda de todo

Una trampa que parece un detalle y no lo es. El valor por defecto de un parámetro se crea una sola vez, cuando se define la función, no cada vez que se la llama:

def registrar(x, acumulada=[]):
    acumulada.append(x)
    return acumulada

registrar(1)  → [1]
registrar(2)  → [1, 2]     # ¡se acordó del anterior!
registrar(3)  → [1, 2, 3]
Las tres llamadas escriben sobre la misma lista, la que quedó guardada en la definición. La forma correcta usa None como marca de «no me pasaron nada» y crea la lista adentro:
def registrar(x, acumulada=None):
    if acumulada is None:
        acumulada = []
    acumulada.append(x)
    return acumulada
Ahora las tres llamadas dan [1], [2] y [3]. La regla para llevarse: nunca pongas una lista o un diccionario como valor por defecto. Con números y textos no pasa, justamente porque son inmutables.
Ejemplo resuelto

¿Por qué este programa imprime [1, 2, 3, 4] y no [1, 2, 3]? a = [1, 2, 3] b = a b.append(4) print(a)

Paso a paso:

a = [1, 2, 3]   → se crea una lista, y a apunta a ella
b = a             → b apunta a la misma, no se crea ninguna nueva
b.append(4)     → se modifica esa única lista
print(a)         → a apunta a la lista modificada: [1, 2, 3, 4]

El punto clave está en la línea 2. Con números, b = a copia el valor. Con listas, copia la dirección: quedan dos nombres para el mismo objeto.

Si querías que fueran independientes:

b = a.copy()

Ahora b.append(4) deja a en [1, 2, 3].

Ojo con una variante que confunde: si en vez de b.append(4) escribieras b = b + [4], a quedaría intacta aunque no hayas copiado. Es que b + [4] crea una lista nueva y le mueve el nombre a b; nunca se toca la original. Modificar y reasignar no son lo mismo.

Control: ante la duda, imprimí las dos variables después de cada línea. Si cambian juntas, comparten lista.

El mismo control, sin mirar contenidos. print(a is b) contesta la pregunta de una: True significa que son la misma lista y que lo que le hagas a una le pasa a la otra. Después de b = a da True; después de c = a.copy() da False aunque a == c siga dando True. Es más directo que comparar impresiones, porque no depende de que las listas tengan valores distintos para notar la diferencia.

Y el mismo fenómeno adentro de una función. Si le pasás la lista a una función que hace lista.append(9), la de afuera queda modificada — el parámetro es otra etiqueta sobre la misma lista. Si la función hace lista = lista + [9], la de afuera no cambia, porque eso arma una lista nueva y le mueve el nombre local. Es la misma regla de siempre, y cuando una función «no hace nada» o «hace de más» sobre una lista, es esto.

Dónde se cae la mayoría

Hasta acá la explicación. La práctica es la otra mitad: 7 ejercicios de este tema, en cuatro niveles, que no te dicen sólo si está bien al final sino que te corrigen en cada paso y te explican por qué. Además trae una animación que muestra la idea en movimiento.

Practicar Mutabilidad y referencias →

Ver todos los temas de Pensamiento Computacional