PythonAprende PythonDocumentación

Programación funcional

map/filter, functools, itertools y funciones puras.

La programación funcional trata el cómputo como la composición de funciones: entradas → salidas, sin estados mutables escondidos. Python no es un lenguaje funcional puro, pero le prestó sus mejores ideas.

Funciones puras: el principio rector

Una función es pura cuando:

  1. Para las mismas entradas devuelve siempre la misma salida
  2. No produce efectos secundarios (no muta nada externo, no imprime, no escribe archivos)
# PURA: determinista, no toca nada externo
def area(base, altura):
    return base * altura

# IMPURA: depende del mundo exterior y lo modifica
total = 0
def acumular(valor):
    global total        # muta estado externo
    total += valor
    return total

Las funciones puras se testean trivialmente, se razonan aisladamente y se paralelizan sin miedo. Aspira a que la mayor parte de tu código sea pura.

map y filter

numeros = [1, 2, 3, 4, 5, 6]

cuadrados = list(map(lambda n: n ** 2, numeros))       # transformar
pares = list(filter(lambda n: n % 2 == 0, numeros))    # filtrar

print(cuadrados)   # [1, 4, 9, 16, 25, 36]
print(pares)       # [2, 4, 6]

map transforma cada elemento; filter conserva los que cumplen. Ambos devuelven iteradores perezosos — por eso los envuelves en list() para verlos.

Verdad incómoda: en Python, las comprehensions suelen preferirse a map/filter por legibilidad:

cuadrados = [n ** 2 for n in numeros]         # equivalente a map
pares = [n for n in numeros if n % 2 == 0]    # equivalente a filter

reduce: plegar a un solo valor

from functools import reduce

numeros = [2, 3, 4, 5]

producto = reduce(lambda acc, n: acc * n, numeros)
print(producto)    # 120 → (((2*3)*4)*5)

reduce acumula: toma dos elementos, los combina en uno, y repite hasta que queda uno solo. Para sumas usa sum() (más claro); para todo lo demás, piensa si un bucle simple no sería más legible.

functools: utilería seria

from functools import lru_cache, partial

@lru_cache(maxsize=None)          # cachea resultados: memoización
def fibonacci(n):
    return n if n < 2 else fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(100))   # instantáneo con caché; siglos sin ella

int2 = partial(int, base=2)       # pre-fijar argumentos
print(int2("1010"))    # 10
  • @lru_cache: convierte funciones recursivas lentas en rápidas con una línea
  • partial: crea versiones especializadas de funciones

itertools: el álgebra de iteradores

from itertools import chain, pairwise, groupby, count

print(list(chain([1, 2], [3, 4])))     # [1, 2, 3, 4] → concatena
print(list(pairwise([1, 2, 3, 4])))    # [(1, 2), (2, 3), (3, 4)]

# agrupar elementos consecutivos por clave
datos = [("a", 1), ("a", 2), ("b", 3)]
for clave, grupo in groupby(datos, key=lambda x: x[0]):
    print(clave, [x[1] for x in grupo])   # a [1, 2] / b [3]

itertools construye pipelines de iteradores con memoria mínima. Combínalo con generadores y procesas gigas de datos sin sudar.

Inmutabilidad donde puedas

# En vez de mutar, construye nuevos valores
def con_descuento(precios, pct):
    return {nombre: precio * (1 - pct) for nombre, precio in precios.items()}

Resumen

  • Función pura: misma entrada → misma salida, sin efectos secundarios
  • map/filter transforman y filtran; en Python la comprehension suele ganar en legibilidad
  • reduce pliega a un valor; sum/max/min son los casos comunes ya resueltos
  • @lru_cache para memoización; partial para especializar funciones
  • itertools + generadores = pipelines con memoria constante

Quiz

  1. 1. ¿Qué es una función pura?

  2. 2. ¿Qué hace functools.reduce(lambda a, b: a + b, [1, 2, 3, 4])?

  3. 3. ¿Qué produce itertools.pairwise([1, 2, 3, 4])?

Ejercicios

Ejercicio 1: map y filter juntos

Usa map y filter (o una combinación equivalente) para imprimir los cuadrados de los números impares del 1 al 10. Resultado: [1, 9, 25, 49, 81]

Cargando editor…

Ejercicio 2: Pipeline con reduce

Usa functools.reduce para calcular el producto de todos los números de la lista [2, 3, 4, 5] e imprimirlo. Resultado: 120

Cargando editor…