54 · Gestión de memoria y Python idiomático
Cómo CPython libera memoria realmente (conteo de referencias + GC cíclico), el truco de __slots__ para clases que consumen mucha memoria, y los pequeños hábitos que separan al Python principiante del código que recibe LGTM en la primera revisión.
CPython usa **conteo de referencias** — cada objeto lleva un contador de cuántos nombres apuntan a él; cuando ese contador llega a cero la memoria se recupera de inmediato, sin pausa de GC. Un recolector de basura cíclico (módulo `gc`) maneja los casos extremos donde dos objetos se apuntan mutuamente y sus contadores nunca llegan a cero por sí solos. Entender esto te libera de invocar `gc.collect()` por costumbre y te ayuda a razonar sobre **dónde** va realmente tu memoria. Combina ese entendimiento con una lista corta de hábitos Pythonics y escribirás código en el que otros ingenieros confían desde la primera lectura.
Sin esto:
Sin un modelo mental del conteo de referencias vas a filtrar objetos sin darte cuenta (manteniendo una lista que sostiene viva la última referencia), llamarás a `gc.collect()` esperando que arregle un pico de 2 GB de memoria que en realidad se debe a un caché que crece, y escribirás bucles que parecen código C — acumulando deuda técnica que se compone cada vez que alguien más abre el archivo.
Cubriste el lenguaje Python — ahora hablemos de escribirlo bien
Puedes escribir Python correcto que otros ingenieros encuentren difícil de leer. También puedes escribir Python elegante que una máquina luche para ejecutar a escala. Esta lección final es sobre la brecha entre funcionar y ser bueno.
Veremos tres temas concretos:
- El modelo de memoria de CPython — conteo de referencias, el GC cíclico y
__slots__ - Conciencia del tamaño — ¿cuánto pesa realmente una lista vacía?
- Hábitos idiomáticos — las pequeñas convenciones que hacen que el código Python sea un placer de revisar
En el camino leeremos el Zen de Python, que no es una broma — es un documento de diseño de una página que vale la pena leer al menos una vez en tu vida como programador.
Python (in browser)
Cada enlace de nombre incrementa el refcount; cada `del` (o salida de scope) lo decrementa. Cero significa que la memoria se libera de inmediato.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`gc.collect()` devuelve el número de objetos inalcanzables que encontró y liberó. En código normal rara vez lo llamas manualmente — Python ejecuta el GC periódicamente en segundo plano.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`__slots__` elimina el `__dict__` por instancia, reduciendo la memoria por objeto en aproximadamente 40–60%. La contrapartida: ya no puedes agregar atributos arbitrarios en tiempo de ejecución.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`sys.getsizeof` mide el tamaño superficial de un objeto — el overhead del contenedor, no los objetos que contiene. Una tupla es más barata que una lista porque no asigna buffer de crecimiento adicional.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Cuatro patrones que aparecen en todo código Python. La columna derecha es más corta, más rápida y lo que los revisores esperan.
Python (in browser)
El Zen de Python es un documento de diseño real, no un meme. "La legibilidad cuenta" ha dado forma a toda API de Python desde 1999. Ejecútalo en cualquier instalación de Python, incluido Pyodide.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
El lenguaje Python es el sustrato; el resto del bootcamp está construido sobre esto. Lo que sigue: estadística, ML, NLP, aprendizaje profundo. Todo lo que escribas de aquí en adelante descansa en las intuiciones que construiste a lo largo de estas 54 lecciones.
¿Qué hace realmente `del x` en CPython?
- CPython usa conteo de referencias: la memoria se libera en el instante en que la última referencia cae a cero. El GC cíclico (módulo `gc`) es un mecanismo de respaldo para ciclos, no el mecanismo principal — no lo trates como una herramienta normal.
- `__slots__` y los generadores son tus dos palancas principales cuando la memoria realmente es escasa (después de perfilar). `__slots__` elimina el overhead de `__dict__` por instancia para clases instanciadas millones de veces; los generadores (capítulo 9) producen valores de forma perezosa en lugar de materializar una lista completa.
- El Zen de Python (`import this`) es un documento de diseño real, no un meme. "La legibilidad cuenta" es la regla única que explica la mayoría de las decisiones de API de Python. Léelo una vez.
- Ahora estás equipado para escribir Python que otros ingenieros puedan leer, revisar y extender. Los idiomas — comprensiones, pruebas de veracidad, `.get()`, `enumerate()`, bloques `with`, imports agrupados — son la diferencia entre un comentario de revisión de 2 líneas y una revisión de 40 comentarios.
Cada línea de cada codebase de ML que leerás alguna vez usa estos idiomas. El `nn.Module` de PyTorch usa `__slots__`. Los datasets de HuggingFace usan generadores. Los bucles de entrenamiento en producción usan `with` para todo — file handles, contextos de GPU, contextos de logging. Cuando empieces a contribuir a un repo de ML existente, el Python idiomático es la diferencia entre feedback como 'LGTM' y una revisión de 40 comentarios.
Si lo quitas: El código que 'funciona' pero no es idiomático es deuda técnica desde el primer día. Tus futuros colegas no confiarán en tus PRs y tus bugs se esconderán a plena vista dentro de bucles que escribiste como código C. Los pequeños hábitos de esta lección son lo que permite a los ingenieros de ML experimentados leer código desconocido a velocidad — se basan en que los patrones sean predecibles.