Nivel: Intermedio+
Tema: Caché, política LRU (Least Recently Used), dict ordenado, diseño de APIs, tests con pytest
Objetivo: Implementar una caché con capacidad limitada que expulsa el elemento menos recientemente usado cuando se llena.
En Python 3.7+ los
dictpreservan el orden de inserción. Usaremos ese comportamiento para simular LRU moviendo claves “usadas” al final.
Enunciado
Crea una clase LRUCache con:
Constructor
LRUCache(capacidad)
Reglas:
- Si
capacidadesNoneo no esint, lanceTypeError. - Si
capacidad<= 0, lanceValueError.
Métodos
get(clave)
- Devuelve el valor asociado a
clavesi existe. - Si no existe, devuelve
None. - Si existe, debe marcar esa clave como “recientemente usada” (moverla al final).
set(clave, valor)
- Inserta o actualiza el par
clave → valor. - Si la clave ya existe, actualiza el valor y marca como usada.
- Si se excede la capacidad, debe expulsar la clave menos recientemente usada.
clavedebe ser hashable; si no, lanceTypeError.
__len__()
- Devuelve el número de elementos en caché.
Ejemplos
cache = LRUCache(2)
cache.set("a", 1)
cache.set("b", 2)
cache.get("a") # 1 (ahora "a" es la más reciente)
cache.set("c", 3) # expulsa "b" (porque "b" es la menos usada)
cache.get("b") # None
cache.get("c") # 3
len(cache) # 2
Pistas
- Usa un
dictinterno:self._data = {} - Para mover una clave al final:
- lee el valor
- elimina la clave
- reinsertarla con el mismo valor
- Para expulsar la menos reciente:
- la primera clave del dict es la menos reciente
- obtén
next(iter(self._data))y elimínala
- Verifica hashability con
hash(clave).
Solución explicada (paso a paso)
- Validamos la capacidad.
set():- validar hashability
- si existe: borrar y reinsertar (mover al final)
- si no existe y está lleno: expulsar la primera clave
- insertar
get():- si existe: mover al final y devolver valor
- si no: devolver
None
__len__: retornarlen(self._data).
Ejecuta:
pytest -q
Variantes para subir de nivel (opcional)
- Método
items()para inspeccionar el estado del caché (para debugging) - Soportar
pop(clave)explícito - Añadir estadísticas (hits/misses/evictions)
- Implementar LRU con lista doblemente enlazada (más “clásico”, O(1) real para mover nodos)
Lo que aprendiste
- Qué es LRU y por qué se usa en sistemas reales
- Cómo usar el orden de inserción de
dictcomo estructura base - Cómo diseñar una clase pequeña con contrato claro
- Cómo testear expulsión y actualización correctamente
Accede al código completo y a los tests en GitHub para ejecutar y modificar la solución localmente.
Si quieres seguir con retos “tipo producción”, el siguiente recomendado es:
Reto #26 — Rate limiter (token bucket simple) para practicar tiempo, estado y lógica defensiva.