Saltar al contenido principal
eLearner.app
Módulo 6 · Lección 3 de 423/36 en el curso~10 min
Lecciones del módulo (3/4)

Generator expressions

Una expresión generadora (generator expression) es similar a una comprensión de lista, pero utiliza paréntesis en lugar de corchetes. La diferencia es drástica: no construye una lista en memoria, sino que produce los elementos bajo demanda, uno a la vez.

Python
gen = (n * n for n in range(1_000_000))
# instantáneo, memoria constante: aún no se ha hecho ningún cálculo

list_comp = [n * n for n in range(1_000_000)]
# asigna 1 millón de enteros en memoria

Evaluación perezosa (lazy evaluation)

El generador no hace nada hasta que alguien le pide el siguiente valor:

Python
gen = (n * n for n in range(5))
next(gen)    # 0    (calculado ahora)
next(gen)    # 1
next(gen)    # 4
# ... y así sucesivamente, hasta StopIteration

El generador se agota: después de consumir todos los elementos, queda vacío para siempre. Para volver a usarlo, debes recrearlo.

Cuándo usarlo

Cuando pasas los resultados a una función que los consume en secuencia:

Python
total = sum(n * n for n in range(1_000_000))
# sin lista intermedia, memoria constante

sum, any, all, max, min, "".join(...) aceptan generadores. Si la función externa solo requiere los paréntesis de llamada, puedes omitir los propios del generador:

Python
sum((n * n for n in range(10)))    # OK
sum(n * n for n in range(10))      # IDÉNTICO, más legible

any y all: cortocircuito

any(...) y all(...) detienen la iteración tan pronto como tienen la respuesta. Con un generador, los elementos siguientes ni siquiera se calculan.

Python
nums = [1, 2, 3, 4, 5]
any(n > 3 for n in nums)    # True (se detiene en 4)
all(n > 0 for n in nums)    # True
all(n > 2 for n in nums)    # False (se detiene en 1)

Patrón: tubería perezosa (lazy pipeline)

Python
righe = (linea.strip() for linea in testo.splitlines())
non_vuote = (r for r in righe if r)
prime_dieci = []
for r in non_vuote:
    prime_dieci.append(r)
    if len(prime_dieci) == 10:
        break

Sin listas intermedias, incluso con entradas gigantescas.

Consumir generadores con sum, any, all

Las expresiones generadoras son perfectas para pasarse directamente a funciones que consumen iterables, como sum(), any() o all(). En este caso, puedes omitir los paréntesis externos de la expresión generadora, simplemente escribiendo:

Python
squares_sum = sum(x**2 for x in range(10))

Esto mantiene tu código limpio y sumamente eficiente en memoria.

Pruébalo tú

Ejercicio#python.m6.l3.e1
Intentos: 0Cargando...

Calcula la suma de los cuadrados de los números del 1 al 100 (inclusive) usando una expresión generadora dentro de sum(). Asígnala a `tot`. Evalúa `tot`.

Cargando editor...
Mostrar pista

range(1, 101) incluye 100.

Solución disponible después de 3 intentos

Ejercicio de repaso

Ejercicio#python.m6.l3.e2
Intentos: 0Cargando...

Dada la lista `words = ['ciao', 'mondo', 'PYTHON', 'java']`, usa any() con una expresión generadora para comprobar si AL MENOS una palabra está en mayúsculas (.isupper()). Asigna el resultado a `has_uppercase`. Evalúa `has_uppercase`.

Cargando editor...
Mostrar pista

any(p.isupper() for p in words)

Solución disponible después de 3 intentos

Desafío adicional

Ejercicio#python.m6.l3.e3
Intentos: 0Cargando...

Usa una expresión generadora pasada directamente a la función `sum()` para calcular la suma de los cuadrados de todos los enteros desde 1 hasta 100 inclusive. Guarda el resultado en `total_sum` y evalúalo.

Cargando editor...
Mostrar pista

Escribe total_sum = sum(x**2 for x in range(1, 101)). No se necesitan dobles paréntesis.

Solución disponible después de 3 intentos