Python itertools: construir pipelines de iteradores perezosos

Python itertools: construir pipelines de iteradores perezosos

itertools es un módulo de la biblioteca estándar que expone bloques de iteración combinables. Su interés no está en sustituir un bucle for por una función de nombre críptico, sino en manipular flujos de datos sin cargarlos nunca por completo en memoria. Cada función devuelve un iterador perezoso: nada se calcula hasta que se consume el resultado. Eso es lo que permite encadenar transformaciones sobre millones de elementos con una huella de memoria constante. ...

29 de mayo de 2026 · 7 min · Anthony
Python collections : Counter, defaultdict, deque y más

Python collections : Counter, defaultdict, deque y más

El módulo collections forma parte de la biblioteca estándar de Python desde la versión 2.4. Proporciona estructuras de datos especializadas que resuelven problemas recurrentes sin ninguna dependencia externa. Sin embargo, muchos desarrolladores siguen escribiendo bucles de conteo, inicializaciones condicionales de claves, o clases Point con campos x, y, z cuando Counter, defaultdict y namedtuple hacen exactamente eso, mejor y de forma más legible. Aquí están las seis estructuras que utilizo regularmente, con los casos en los que realmente marcan la diferencia. ...

22 de mayo de 2026 · 7 min · Anthony
Python operator: itemgetter, attrgetter y el arte de reemplazar las lambdas

Python operator: itemgetter, attrgetter y el arte de reemplazar las lambdas

La librería operator forma parte de la biblioteca estándar de Python desde siempre, y aun así muchos desarrolladores siguen escribiendo lambda x: x[0] o lambda obj: obj.nombre cuando una función de operator haría el mismo trabajo, de forma más rápida y más legible. Entender qué ofrece esta librería, y cómo está implementada, cambia la manera de escribir código funcional en Python. Qué contiene operator operator expone funciones que corresponden a los operadores del lenguaje. operator.add(2, 3) es el equivalente funcional de 2 + 3, operator.lt(a, b) corresponde a a < b. El interés no es reemplazar los operadores en código aritmético ordinario, sería absurdo. El interés es poder pasar una operación como argumento a una función de orden superior (map, filter, sorted, reduce, functools.partial). ...

20 de mayo de 2026 · 7 min · Anthony
Vistas materializadas vs cache Django para queries lentas

Vistas materializadas vs cache Django para queries lentas

El instinto ante un endpoint de reporting lento suele ser el cache. Un @cache_page, un cache.set(), y el problema parece desaparecer hasta la próxima expiración. Este enfoque tiene una limitación estructural que las vistas materializadas PostgreSQL resuelven desde la raíz. El problema del cache en los endpoints analíticos El cache Django almacena el resultado de una vista Python. La consulta SQL costosa se ejecuta igualmente en cada expiración del cache. Para un informe construido sobre múltiples JOINs y agregaciones, eso significa que el primer usuario tras cada cache miss espera varios segundos. ...

13 de mayo de 2026 · 4 min · Anthony
Optimizar las consultas Django ORM con defer(), only() y Prefetch()

Optimizar las consultas Django ORM con defer(), only() y Prefetch()

Por defecto, Django carga todos los campos de un modelo en cada consulta. En una vista de lista con 50 artículos, eso significa obtener el contenido completo, el resumen, los metadatos y los campos de traducción 50 veces, aunque solo se muestre el título y la fecha. Cuatro métodos QuerySet de Django permiten controlar exactamente qué se carga: defer(), only(), values_list() y Prefetch(). El resultado: 2 consultas SQL en lugar de N+2, con únicamente las columnas necesarias. ...

8 de mayo de 2026 · 6 min · Anthony
Django select_for_update(): bloqueo de filas en transacciones concurrentes

Django select_for_update(): bloqueo de filas en transacciones concurrentes

Dos peticiones simultáneas leen el stock de un producto, las dos ven que queda una unidad, y las dos confirman el pedido. El stock baja a -1. Este tipo de condición de carrera es casi imposible de reproducir en desarrollo y devastador en producción. select_for_update() es la respuesta de Django: adquirir un bloqueo SQL en el momento de la lectura para garantizar que ninguna otra transacción pueda modificar la fila antes de que termine la operación actual. ...

6 de mayo de 2026 · 4 min · Anthony
Python __slots__: reduce la memoria de tus instancias entre un 40 y un 60%

Python __slots__: reduce la memoria de tus instancias entre un 40 y un 60%

Por defecto, Python asigna un diccionario __dict__ a cada instancia de una clase. Es flexible, sí. Pero cuando se tienen miles o millones de objetos en memoria al mismo tiempo, ese coste se acumula rápidamente. __slots__ elimina ese diccionario y reemplaza el almacenamiento por instancia con descriptores internos más compactos. Resultado típico: entre un 40 y un 60 por ciento menos de memoria por instancia. Lo que hace Python sin slots Sin ninguna declaración especial, cada instancia lleva su propio __dict__: ...

6 de mayo de 2026 · 4 min · Anthony
Renombrar campos del ORM de Django con F() en values()

Renombrar campos del ORM de Django con F() en values()

Cuando se exponen datos desde un modelo Django hacia una API o un serializer, los nombres de los campos del modelo no siempre coinciden con lo que se quiere devolver. El enfoque habitual: recuperar las instancias y renombrar en Python. Existe una opción mejor: dejar que la base de datos haga el trabajo usando F() dentro de values(). El problema: los nombres de campo del modelo se imponen class Task(models.Model): name = models.CharField(...) created_at = models.DateTimeField(...) Si queremos devolver nombre_tarea en lugar de name, lo habitual es recuperar los datos y renombrar en Python, ya sea con una comprensión de diccionario o dentro del serializer. En cualquier caso, la transformación ocurre a posteriori, en memoria. ...

5 de mayo de 2026 · 3 min · Anthony
Django Window Function vs GROUP BY: QuerySets encadenables

Django Window Function vs GROUP BY: QuerySets encadenables

Con el ORM de Django hay dos formas de añadir un valor calculado sobre un conjunto de filas: annotate() con una agregación clásica (Max, Count, Sum…) o annotate() con una Window function. A simple vista se parecen. En la práctica, su comportamiento es fundamentalmente distinto — y elegir la opción equivocada puede bloquear toda la cadena de filtrado. GROUP BY con annotate(): filas que se comprimen Cuando combinamos values() y annotate() con una agregación, Django genera un GROUP BY en SQL. El resultado: las filas se agrupan y obtenemos una fila por grupo. ...

4 de mayo de 2026 · 4 min · Anthony
Django in_bulk(): por qué es mejor que filter() en masa

Django in_bulk(): por qué es mejor que filter() en masa

Cuando tenemos una lista de identificadores y queremos recuperar las instancias correspondientes, el reflejo habitual en Django es filter(pk__in=[...]). Funciona — una sola consulta SQL. Pero in_bulk() es una optimización ORM frecuentemente ignorada: retorna un diccionario {id: instancia} en lugar de un QuerySet, lo que cambia radicalmente la forma de acceder a los resultados. Donde filter() obliga a un recorrido O(n) para encontrar un objeto por su ID, in_bulk() da acceso directo O(1). ...

4 de mayo de 2026 · 4 min · Anthony

Newsletter

Recibe los nuevos artículos directamente en tu bandeja de entrada.

Sin spam. Baja en un clic.