logo para rammsesitic

Python Under the Hood: Memoria, Mutabilidad y el "Engaño" de las Variables


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.

Objeto_es_Rey.py
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.

Inmutables.py
a = 1
print(id(a)) # Imprime la dirección de memoria 11755688

a = 3
print(id(a)) # Imprime la dirección de memoria 11755752
Mutabilidad.py
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, set

El 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