El Objeto es el Rey: Heterogeneidad en Listas.
Una pregunta básica que te debes hacer si trabajas con python es: ¿Cómo puede una lista de python almacenar un entero, un booleano, un string y otros tipos de datos al mismo tiempo sin explotar?
La respuesta esta en la arquitectura de punteros. Python no guarda los datos de forma contigua. Almacena direcciones de memoria de 64 bits. A ojos de la lista, tiene varios objetos del mismo tamaño y tipo, aunque en realidad sean completamente distintos.
arr = [1, True, "str", 0.4, None]Inmutabilidad vs Mutabilidad: El ID es la clave.
Es común creer que a += 1 modifique la variable a. Error.
- Objetos Inmutables (int, str, tuple). Cuando modificas una variable solo estas moviendo la "etiqueta". Supongamos lo siguiente; Tenemos a = 1, hacemos un print(id(a)). Eso imprime algo como; 11755688. Siendo esta la dirección de memoria para "1", al modificar la variable a = 3, su dirección cambia para apuntar al "3" regresando un número distinto; 11755752. Dejando al "1" a la espera de que el Garbage Collector lo elimine de la memoria.
a = 1
print(id(a)) # Imprime la dirección de memoria 11755688
a = 3
print(id(a)) # Imprime la dirección de memoria 11755752- Objetos Mutables (list, dict, set). Son estructuras dinámicas. Se pueden modificar sin que su dirección de memoria se vea afectada, permitiendo interacciones como la siguiente:
arr = [1, True, "str", 0.4, None]
arr1 = arr
# Output.
# Arr: 127901588179776, arr1: 127901588179776
print(f"Arr: {id(arr)}, arr1: {id(arr1)}")
# Modificar arr1 afecta tambien arr
arr1[0] = 987
# Output.
# [987, True, "str", 0.4, None]
print(arr)
# El comportamiento anterior lo comparten
# dict, setEl Peligro de las Referencias Compartidas.
Retomando la interacción que hay en la memoria con los objetos mutables, se debe tener cuidado con bugs ocultos que se nos podrían pasar. Ya que hacer arr1 = arr estamos haciendo que dos etiquetas hagan referencia al mismo objeto fisico en memoria.
El problema de la copia superficial (Shallow Copy).
Incluso usando .copy(), podrías tener problemas si tienes listas anidadas:
lista_original = [ [1, 2], [3, 4] ]
Ya que los elementos que la conforman siguen siendo dos listas mutables.
Resumén.
Variables. Son nombres que apuntan a objetos
Listas. Son arrays de punteros (por eso aceptan de todo).
Mutabilidad. Decide si el objeto cambia "in-place" o si se crea uno nuevo.
Asignación. a = b siempre copia la referencia, nunca el valor
