Los cálculos "a demanda" o cálculos perezosos se hicieron populares con el aumento de los volúmenes de datos procesados. En Python, estos mecanismos se implementaron en la biblioteca estándar a través de generadores e iteradores, más tarde — mediante la función itertools y clases que pueden entregar un elemento a la vez bajo demanda, evitando almacenar todos los datos en memoria de inmediato.
La construcción habitual de colecciones requiere cargar en memoria todo el resultado. Si el volumen es grande, el programa puede "caer" o funcionar muy lentamente. Es importante saber manejar flujos de datos — por ejemplo, archivos de varios gigabytes o resultados de solicitudes a API.
Los cálculos perezosos permiten obtener elementos según sea necesario. En Python, esto se facilita mediante el uso de generadores, la sintaxis yield, expresiones generadoras, funciones map, filter, zip, así como el módulo itertools. Este enfoque se basa en el protocolo de iteradores.
Ejemplo de código:
def huge_sequence(): for i in range(1, 10**9): yield i * i for val in huge_sequence(): if val > 100: break print(val)
Características clave:
¿Siempre los generadores en Python ahorran memoria?
Respuesta: No, solo si los datos realmente no requieren almacenamiento intermedio entre pasos. Algunas construcciones, como las list comprehensions, crean toda la lista de inmediato, mientras que los generadores — solo bajo demanda. Si los resultados intermedios son necesarios de todos modos, el ahorro se pierde.
Ejemplo:
squares = (x**2 for x in range(10**8)) # perezoso, económico result = list(squares) # consume toda la memoria de inmediato
¿Es cierto que map y filter siempre devuelven listas?
No, en Python 3, map y filter devuelven no una lista, sino un iterador (generador perezoso), lo que ahorra memoria y permite procesar datos "en vuelo".
¿Se puede iterar múltiples veces sobre un generador?
No, el generador "se agota" después de un recorrido completo. Si se necesita un recorrido repetido, es mejor crear un nuevo generador o usar una colección contenedora, cuyo contenido se puede recorrer múltiples veces.
Un desarrollador intenta procesar un gran archivo de registro, cargándolo en memoria como una lista de cadenas.
Ventajas:
Desventajas:
Se utiliza un generador — lectura línea por línea del archivo con procesamiento de cada línea a medida que se recibe.
Ventajas:
Desventajas: