Saltar al contenido
Portada » Lenguajes » 12. Programación Funcional en Python

12. Programación Funcional en Python

Programación Funcional en Python. La programación funcional es una forma de escribir programas en la que usamos funciones para procesar datos, de manera similar a cómo usamos fórmulas matemáticas. La idea principal es evitar cambiar los datos directamente y trabajar con copias de ellos en lugar de modificarlos.

Python es un lenguaje flexible que permite combinar diferentes estilos de programación, y la programación funcional es uno de ellos. En este capítulo, haremos una pequeña introducción a las herramientas especiales que puedes utilizar en Python.

Empecemos.

Map, Filter y Reduce

Las funciones map(), filter() y reduce() son herramientas esenciales en la programación funcional que permiten transformar y filtrar datos de manera sencilla.

map()

La función map() aplica una función dada a cada ítem de un iterable (como una lista) y devuelve un nuevo iterable con los resultados.

Ejemplo de uso:
# Función que se aplicará
def cuadrado(x):
return x ** 2

# Lista de números
numeros = [1, 2, 3, 4, 5]

# Aplicar la función cuadrado a cada número
resultado = map(cuadrado, numeros)

# Convertir el resultado a una lista
print(list(resultado)) # Salida: [1, 4, 9, 16, 25]
filter()

La función filter() crea un iterable que contiene solo los elementos del iterable original para los cuales la función dada devuelve True.

Ejemplo de uso:
# Función que verifica si un número es par
def es_par(x):
return x % 2 == 0

# Lista de números
numeros = [1, 2, 3, 4, 5, 6]

# Filtrar números pares
resultado = filter(es_par, numeros)

# Convertir el resultado a una lista
print(list(resultado)) # Salida: [2, 4, 6]
reduce()

La función reduce() no está incluida en el espacio de nombres global de Python 3, pero se puede importar desde el módulo functools. Por lo tanto tendrás que utilizar pip para instalar el módulo, pero seguro que a estas alturas ya sabes hacerlo. reduce() plica una función de manera acumulativa a los elementos de un iterable, reduciéndolo a un solo valor.

Ejemplo de uso:
from functools import reduce

# Función que suma dos números
def suma(x, y):
return x + y

# Lista de números
numeros = [1, 2, 3, 4, 5]

# Reducir la lista a la suma total
resultado = reduce(suma, numeros)

print(resultado) # Salida: 15

Uso de Generadores (yield)

Los generadores son una forma de crear iteradores de manera sencilla utilizando la palabra clave yield. En lugar de devolver un valor y terminar la función, yield permite pausar la ejecución y volver a continuar desde el mismo punto, ahorrando memoria y recursos.

Ejemplo de generador:
def conteo_regresivo(n):
while n > 0:
yield n # Pausa la función y devuelve n
n -= 1

# Crear un generador
contador = conteo_regresivo(5)

# Iterar sobre el generador
for numero in contador:
print(numero)
# Salida:
# 5
# 4
# 3
# 2
# 1

Iteradores

Un iterador es un objeto que implementa el protocolo de iteración de Python, permitiendo recorrer su contenido. Un iterador debe implementar los métodos __iter__() y __next__(). Los generadores son una forma conveniente de crear iteradores sin necesidad de implementar estos métodos manualmente.

Ejemplo de un iterador personalizado:
class Contador:
def __init__(self, limite):
self.limite = limite
self.contador = 0

def __iter__(self):
return self

def __next__(self):
if self.contador < self.limite:
self.contador += 1
return self.contador
else:
raise StopIteration # Señala que no hay más elementos

# Crear un objeto iterador
contador = Contador(5)

# Iterar sobre el objeto
for numero in contador:
print(numero)
# Salida:
# 1
# 2
# 3
# 4
# 5

functools.partial

Permite crear nuevas funciones basadas en funciones existentes, fijando algunos de los argumentos de la función original. Es útil para simplificar llamadas repetitivas con parámetros comunes.

Ejemplo:

from functools import partial

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

# Creamos una función que siempre eleva al cuadrado
cuadrado = partial(potencia, exponente=2)

print(cuadrado(5)) # Salida: 25

itertools (Iteradores Funcionales)

El módulo itertools proporciona herramientas poderosas para trabajar con iteradores y secuencias de datos.

Funciones importantes:

  • itertools.chain: Combina varias iterables en una sola.
  • itertools.permutations: Genera todas las permutaciones posibles de un iterable.
  • itertools.combinations: Genera combinaciones únicas de un iterable.
  • itertools.groupby: Agrupa datos similares en iteradores consecutivos.

Ejemplo:

from itertools import combinations

# Generar combinaciones únicas de una lista
numeros = [1, 2, 3, 4]
combinaciones = list(combinations(numeros, 2))
print(combinaciones) # Salida: [(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]

operator

El módulo operator proporciona funciones predefinidas que equivalen a operadores básicos, permitiendo escribir código más limpio y funcional.

Funciones importantes:

  • operator.add: Suma dos números.
  • operator.mul: Multiplica dos números.
  • operator.itemgetter: Recupera un elemento de una lista o diccionario.
  • operator.attrgetter: Obtiene atributos de un objeto.

Ejemplo:

from operator import add

numeros = [1, 2, 3, 4]
resultado = list(map(add, numeros, numeros))
print(resultado) # Salida: [2, 4, 6, 8]

all y any

Estas funciones permiten evaluar condiciones lógicas en iterables.

  • all(iterable): Retorna True si todos los elementos del iterable son verdaderos.
  • any(iterable): Retorna True si al menos un elemento del iterable es verdadero.

Ejemplo:

numeros = [1, 2, 3, 0]
print(all(numeros)) # Salida: False (porque 0 es falso)
print(any(numeros)) # Salida: True (porque hay al menos un elemento verdadero)

Expresiones de Comprensión

Aunque no son exclusivas de la programación funcional, las comprensiones de listas, conjuntos y diccionarios son herramientas poderosas para transformar y filtrar datos en una línea de código.

Ejemplo:

# Crear una lista de cuadrados
cuadrados = [x ** 2 for x in range(1, 6)]
print(cuadrados) # Salida: [1, 4, 9, 16, 25]

filterfalse del módulo itertools

Es similar a filter, pero en lugar de seleccionar los elementos donde la condición es verdadera, selecciona los que son falsos.

Ejemplo:

from itertools import filterfalse

# Filtrar números que NO son pares
numeros = [1, 2, 3, 4, 5]
impares = list(filterfalse(lambda x: x % 2 == 0, numeros))
print(impares) # Salida: [1, 3, 5]

zip

Permite emparejar elementos de múltiples iterables, lo que es útil para combinar datos de manera funcional.

Ejemplo:

nombres = ["Ana", "Juan", "Luis"]
edades = [25, 30, 35]

# Combinar listas en una sola estructura
personas = list(zip(nombres, edades))
print(personas) # Salida: [('Ana', 25), ('Juan', 30), ('Luis', 35)]

Resumen


La programación funcional en Python ofrece herramientas para transformar y manipular datos. Funciones como map(), filter(), y reduce() permiten aplicar operaciones en colecciones de datos de forma concisa. Además, el uso de generadores y la comprensión de iteradores facilitan la creación de flujos de datos que son eficientes en memoria y fáciles de manejar. Incorporar estos conceptos en el desarrollo de Python puede resultar en un código más limpio, legible y mantenible.


Pasemos a la parte práctica.

Ejercicio 1: Uso de map para transformar una lista

Tienes una lista de temperaturas en grados Celsius: [0, 10, 20, 30, 40]. Escribe un programa que convierta estas temperaturas a grados Fahrenheit usando la función map. La fórmula para la conversión es:

F = C * (9/5) + 32
# Lista de temperaturas en Celsius
temperaturas_celsius = [0, 10, 20, 30, 40]

# Función para convertir Celsius a Fahrenheit
def celsius_a_fahrenheit(celsius):
    return celsius * 9 / 5 + 32

# Usamos map para aplicar la conversión a toda la lista
temperaturas_fahrenheit = list(map(celsius_a_fahrenheit, temperaturas_celsius))

print("Temperaturas en Fahrenheit:", temperaturas_fahrenheit)

Explicación:

  • Definimos una lista de temperaturas en Celsius.
  • Creamos una función celsius_a_fahrenheit que realiza la conversión.
  • Utilizamos map para aplicar esta función a cada elemento de la lista, transformándola a Fahrenheit.
  • Convertimos el resultado de map a una lista y lo imprimimos.
Ejercicio 2: Uso de filter para filtrar números pares

Dada una lista de números del 1 al 20, escribe un programa que filtre los números pares utilizando la función filter.
# Lista de números del 1 al 20
numeros = list(range(1, 21))

# Función para verificar si un número es par
def es_par(numero):
    return numero % 2 == 0

# Usamos filter para quedarnos solo con los números pares
numeros_pares = list(filter(es_par, numeros))

print("Números pares:", numeros_pares)

Explicación:

  • Creamos una lista de números del 1 al 20.
  • Definimos una función es_par que devuelve True si un número es par.
  • Utilizamos filter para aplicar esta función a cada número de la lista, filtrando solo los números pares.
  • Convertimos el resultado de filter a una lista y la mostramos
Ejercicio 3: Creación de un generador con yield

Escribe un generador que devuelva los cuadrados de los números del 1 al 10. Usa un bucle for para iterar sobre los valores generados y mostrar cada uno.
# Generador para los cuadrados de los números
def generador_cuadrados(n):
    for i in range(1, n + 1):
        yield i ** 2

# Usamos el generador
print("Cuadrados de los números del 1 al 10:")
for cuadrado in generador_cuadrados(10):
    print(cuadrado)

Explicación:

  • Creamos un generador generador_cuadrados que calcula los cuadrados de los números del 1 al n utilizando yield.
  • El generador produce un valor a la vez cuando es iterado.
  • Utilizamos un bucle for para consumir los valores del generador y mostrarlos en pantalla.

Bibliografía de Python de interés.

Logo Python. Programación Funcional en Python

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *