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)
: RetornaTrue
si todos los elementos del iterable son verdaderos.any(iterable)
: RetornaTrue
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
map
para transformar una listaTienes 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
.
filter
para filtrar números paresDada 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 devuelveTrue
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.
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 aln
utilizandoyield
. - 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.
- Curso de Programación Python. Autor: Arturo Montejo Ráez y Salud María Jiménez Zafra (Editorial Anaya)
- Aprende Python desde cero hasta avanzado. Autor: Xavier Reyes Ochoa (Editorial Book Shelter GmbH)
- Aprende la Programación Orientada a Objetos con el lenguaje Python. Autor: Vincent Boucheny (Editorial Ediciones ENI)
- 100 Ejercicios Python para praticar. Autor: Laurentine K.Masson (Editorial: Publicación Independiente).