Dominando yield en Python: Generadores vs Return – Guía práctica
Dominando yield en Python: Generadores vs Return – Guía práctica
¿Qué es yield en Python?
La palabra clave yield se comporta como return, pero en lugar de devolver un valor inmediatamente, devuelve un objeto generador que puede iterarse. Cuando se invoca una función que contiene yield, la ejecución se pausa en la primera sentencia yield y devuelve el control al llamador con un generador. Las llamadas subsiguientes a next() o un bucle for reanudan la ejecución desde ese punto, produciendo el siguiente valor.
Puntos clave
- Yield crea un generador, permitiendo evaluación perezosa (lazy evaluation).
- Los generadores son eficientes en memoria para secuencias grandes o infinitas.
- La lectura de un generador puede hacerse con
for-in,list()onext(). - Una vez agotado, un generador no puede reutilizarse; llama a la función de nuevo.
Sintaxis
yield expresion
Ejemplo práctico: Un yield simple
def prueba_yield():
yield "Bienvenido a Tutoriales Python Guru99"
salida = prueba_yield()
print(salida)
Salida:
<generator object prueba_yield at 0x00000028265EB9A8>
El objeto generador contiene el valor producido. Para acceder a él, itera:
for valor in salida:
print(valor)
Salida:
Bienvenido a Tutoriales Python Guru99
Generadores explicados
Una función generadora es una función especial que devuelve un objeto generador iterable. A diferencia de las funciones regulares que devuelven un solo valor, un generador produce una secuencia de valores perezosamente, generando cada uno solo cuando se solicita.
Creando una función generadora
def generador_ejemplo():
yield "H"
yield "E"
yield "L"
yield "L"
yield "O"
for letra in generador_ejemplo():
print(letra)
Salida:
H E L L O
Función normal vs función generadora
Considera el siguiente par de funciones:
# Función normal
def normal_test():
return "Hola Mundo"
# Función generadora
def generador_test():
yield "Hola Mundo"
print(normal_test()) # → Hola Mundo
print(generador_test()) # → <generator object generador_test>
Las funciones normales terminan en return; los generadores se pausan en yield, devolviendo el control al llamador con un objeto generador.
Consumiendo un generador
Puedes extraer valores de un generador usando:
- Bucles
for-in list()para materializar todos los valoresnext()para paso manual
Ejemplo: Números pares
def numeros_pares(n):
for x in range(n):
if x % 2 == 0:
yield x
print(list(numeros_pares(10))) # → [0, 2, 4, 6, 8]
Usando for-in
for num in numeros_pares(10):
print(num)
Salida:
0 2 4 6 8
Usando next()
gen = numeros_pares(10)
for _ in range(6):
try:
print(next(gen))
except StopIteration:
print("Fin del generador")
Salida:
0 2 4 6 8 Fin del generador
Los generadores son de un solo uso
Una vez que un generador se ha iterado completamente, se agota. Re-iterar no produce nada a menos que se llame de nuevo a la función generadora.
gen = numeros_pares(10)
for num in gen:
print(num)
print(list(gen)) # → []
Yield en acción: Serie de Fibonacci
def serie_fibonacci(limite):
a, b = 0, 1
contador = 0
while contador < limite:
yield a
a, b = b, a + b
contador += 1
fib = serie_fibonacci(7)
for num in fib:
print(num)
Salida:
0 1 1 2 3 5 8
Llamando a una función que produce yield
A continuación, elevamos números al cuadrado usando una función auxiliar y un generador que produce cada resultado.
def cuadrado(n):
return n * n
def rango_cuadrado(n):
for i in range(n):
yield cuadrado(i)
for valor in rango_cuadrado(10):
print(valor)
Salida:
0 1 4 9 16 25 36 49 64 81
Cuándo usar yield en lugar de return
- Procesamiento de datos grandes o en streaming donde cargar todos los elementos a la vez es impracticable.
- Generación de secuencias potencialmente infinitas (p. ej., lectores de archivos perezosos).
- Mejorar la huella de memoria y el tiempo de inicio para conjuntos de datos considerables.
- Cuando necesitas pausar y reanudar la computación, no solo devolver un valor final.
Yield vs. Return – Referencia rápida
| Yield | Return |
|---|---|
| Devuelve un generador; la ejecución se reanuda en la iteración. | Termina la función; devuelve un solo valor inmediatamente. |
Se pausa en cada yield, conservando memoria. | Asigna memoria para el valor devuelto. |
| Ideal para secuencias grandes o infinitas. | Adecuado para resultados pequeños y discretos. |
| Tiempo de ejecución más rápido para grandes conjuntos de datos. | Puede incurrir en sobrecarga al manejar datos enormes. |
Conclusiones clave
- Yield produce un objeto generador, no un valor.
- Los generadores entregan valores perezosamente, manteniendo el uso de memoria mínimo.
- Lee valores mediante
for-in,list()onext(). - Una vez agotados, los generadores deben recrearse para reutilizarse.
- Yield supera a return para datos grandes o en streaming.
python
- Funciones lambda en Python: Guía práctica de funciones anónimas
- Generadores en Python: Iteración Eficiente y Casos de Uso Avanzados
- Explicación de Closures en Python: Cómo las Funciones Anidadas Capturan Variables
- Dominando Decoradores en Python: Mejora Funciones con Técnicas Expertas
- Domine el Método strip() de Python: Guía Completa y Ejemplos Prácticos
- Python len(): Guía Práctica para Medir Longitud de Objetos
- Dominando las funciones lambda en Python: ejemplos prácticos y mejores prácticas
- Función round() en Python explicada con ejemplos prácticos
- Dominando la función map() de Python: sintaxis, ejemplos y mejores prácticas
- Counter de collections en Python: conteo eficiente, actualización y operaciones aritméticas
- Dominando enumerate() en Python: bucles con índices para listas, tuplas, cadenas y diccionarios