Funciones y Generadores

 

1. ¿Qué es una función?

Una función es un bloque de código reutilizable que realiza una tarea. Se define con def.

def saludar(nombre):
    return f"Hola, {nombre}"

Ventajas de usar funciones

  • Reutilización de código

  • Organización y claridad

  • Evitan duplicación

  • Facilitan pruebas y mantenimiento

2. Parámetros y valores por defecto

def potencia(base, exponente=2):
    return base ** exponente

print(potencia(5))      # 25
print(potencia(5, 3))   # 125

3. Funciones con número variable de argumentos

*args (argumentos posicionales)

def sumar(*numeros):
    return sum(numeros)

print(sumar(1, 2, 3, 4))

**kwargs (argumentos con nombre)

def mostrar_info(**datos):
    for clave, valor in datos.items():
        print(clave, ":", valor)

mostrar_info(nombre="Ana", edad=22)

Generadores

Un generador es una función especial que produce valores uno a uno, sin almacenarlos todos en memoria. Se crean usando la palabra clave yield.

¿Por qué son útiles?

  • Consumen muy poca memoria

  • Ideales para procesar grandes cantidades de datos

  • Se evalúan bajo demanda (lazy evaluation)

Ejemplo básico de generador

def contador(n):
    for i in range(1, n + 1):
        yield i

for numero in contador(5):
    print(numero)

Salida:

1
2
3
4
5

Generadores por comprensión (generator expressions)

cuadrados = (x*x for x in range(10))
print(next(cuadrados))
print(next(cuadrados))

ACTIVIDAD PRÁCTICA: “Procesador eficiente de logs”

Objetivo: que tus alumnos entiendan cuándo un generador es mejor que una lista, usando un caso real de FP: procesar archivos de logs grandes.

Enunciado

Dispones de un archivo de logs con miles de líneas. Cada línea tiene este formato:

[INFO] Usuario Ana inició sesión
[ERROR] Fallo en la conexión
[WARNING] Espacio en disco bajo

Debes:

  1. Crear una función generadora que lea el archivo línea a línea.

  2. Crear una función que filtre solo las líneas que contengan "ERROR".

  3. Mostrar los errores encontrados.

  4. Contar cuántos errores hay.

Pista

  • Usa yield para devolver cada línea sin cargar todo el archivo.

  • Usa un generador para filtrar.

Solución propuesta

# 1. Generador que lee el archivo línea a línea
def leer_logs(ruta):
    with open(ruta, "r", encoding="utf-8") as f:
        for linea in f:
            yield linea.strip()

# 2. Generador que filtra solo errores
def filtrar_errores(lineas):
    for linea in lineas:
        if "ERROR" in linea:
            yield linea

# 3. Uso de los generadores
ruta = "logs.txt"

lineas = leer_logs(ruta)
errores = filtrar_errores(lineas)

# 4. Mostrar errores y contarlos
contador = 0
for e in errores:
    print(e)
    contador += 1

print(f"\nTotal de errores: {contador}")

Resultado esperado (ejemplo)

[ERROR] Fallo en la conexión
[ERROR] Usuario Pedro no autorizado

Total de errores: 2