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.
La explicación
La sorpresa
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é
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[:] # 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
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.
nueva = lista.copy()
nueva.append(0)
return nueva
Modificar contra reasignar
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 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:
acumulada.append(x)
return acumulada
registrar(1) → [1]
registrar(2) → [1, 2] # ¡se acordó del anterior!
registrar(3) → [1, 2, 3]
None como marca de «no me pasaron nada» y crea la lista adentro:
if acumulada is None:
acumulada = []
acumulada.append(x)
return acumulada
[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.
¿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:
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:
Ahora b.append(4) deja a en [1, 2, 3].
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.
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
- Creer que b = a copia la lista. No copia: son dos nombres para la misma.
- Modificar una lista adentro de una función sin darse cuenta de que cambia la de afuera.
- Confundir modificar (append, sort) con reasignar (b = [...]): la primera se ve afuera, la segunda no.
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 →