Ir al contenido principal

Python reduce(): Una guía completa

Aprende cuándo y cómo utilizar la función reduce() de Python. Incluye ejemplos prácticos y mejores prácticas.
Actualizado 28 oct 2025  · 11 min de lectura

La función « reduce() » de Python proviene del mundo de la programación funcional. La programación funcional (FP) es un paradigma de programación en el que los programas generan resultados aplicando funciones a datos inmutables.

Un patrón común en este estilo es el «pliegue», que reduce una secuencia a un único resultado. Por ejemplo, doblar la lista de números [2, 4, 5, 3] bajo la suma 14 a través de pasos sucesivos: [2, 4, 5, 3] → [6, 5, 3] → [11, 3] → 14.

reduce() generaliza esta idea. Aplica una operación binaria a un iterable hasta que solo queda el resultado.

En este artículo, exploraré los elementos clave de la programación orientada a objetos ( reduce(), OOP) en Python y daré algunos ejemplos prácticos. Si necesitas refrescar tus conocimientos básicos sobre Python, te recomiendo que consultes estos recursos:

Historia

Python incluye otras funciones de programación funcional en Python, como map() y filter().

Las construcciones funcionales como map() y filter() estaban en Python 1.0. A Guido van Rossum no les gustaba, señalando que reduce() era difícil de analizar, y que un bucle for casi siempre es más legible.  En Python 3.0, siguiendo la PEP 3100, los programadores eliminaron reduce() como función integrada y lo trasladaron al módulo functools. Este cambio a functools básicamente lo degradó a la categoría de herramienta especializada.

¿Por qué utilizar reduce()?

La mayoría de las veces, creo que probablemente sea mejor opción utilizar un bucle o una función integrada. Sin embargo, reduce() sigue siendo una buena opción en algunos casos de uso.

  • Funcionan como tuberías. Encadenar una serie (posiblemente dinámica) de transformaciones de forma limpia.
  • Pliegues algebraicos. Úsalo para operaciones que tienen valores de identidad naturales, como la unión de conjuntos con el conjunto vacío o las operaciones de máscara de bits con cero.
  • Plegado personalizado sin incorporado. Define tu propia fusión de forma específica para cada dominio cuando no exista ninguna integrada.
  • Acumuladores estructurados. Programa simultáneamente varios elementos de estado dentro de una función acumuladora personalizada.

Cómo funciona la función reduce() de Python

Exploremos el funcionamiento de reduce().

La firma de la función básica de reduce() es

functools.reduce(function, iterable, [initializer])

La función reduce() función toma dos argumentos obligatorios y un tercero opcional.

  • function: una función binaria que especifica cómo combinar dos elementos,
  • iterable: la secuencia o iterable que se va a reducir, como una lista o una tupla. initializer(opcional): un valor inicial para sembrar la función.

Ejemplo paso a paso:

  •  [1, 3, 2, 7] → [4, 2, 7].
  • [4, 2, 7] → [6, 7].
  • [6, 7] → [13].

El resultado final es 13.

Ejemplos sencillos de reduce()

Los siguientes ejemplos ilustrativos muestran cómo utilizar reduce().

from functools import reduce

numbers = [2, 4, 6]
product = reduce(lambda x, y: x * y, numbers)  # ((2 x 4) x 6) = 8 x 6 = 48
min_value = reduce(lambda x, y: x if x < y else y, numbers) # 2

words = ['dog', 'cat', 'tree', 'pony']
str_concat = reduce(lambda x, y: x + y, words)  # "dogcattreepony"

Inicializador

Sin un inicializador, reduce() toma el primer elemento del iterable como su valor inicial. Si el iterable está vacío, reduce() lanza un TypeError. Para que el código sea robusto, proporciona un inicializador para definir el comportamiento ante una entrada vacía.

from functools import reduce

words = []
# Error: reduce() of empty iterable with no initial value
str_concat = reduce(lambda x, y: x + y, words)

# Correct: use empty string initializer
str_concat = reduce(lambda x, y: x + y, words, "")

Los inicializadores también generan un resultado con un contenedor vacío. Por ejemplo, puedes concatenar palabras en una lista plana de caracteres. 

from functools import reduce

words = ['reduce', 'is', 'fun']
chars_list = reduce(lambda acc, word: acc + list(word), words, [])
print(chars_list)  # ['r', 'e', 'd', 'u', 'c', 'e', 'i', 's', 'f', 'u', 'n']

Para explorar más a fondo Python y la manipulación de datos, aquí tienes algunas opciones que te recomiendo.

Definición del reductor

Hasta ahora, hemos utilizado funciones lambda para definir el operador binario. 

También puedes utilizar operadores del módulo operator.  El módulo operator contiene versiones funcionales de operadores comunes y llamadas a métodos. Por ejemplo, en lugar de x + y, operator.add(x, y). Esto te permite pasar operadores predefinidos (y eficientes) a reduce() sin necesidad de escribir una lambda.

from functools import reduce
import operator as op

numbers = [2, 4, 6]
total = reduce(op.add, numbers, 0)  # instead of reduce(lambda x,y: x + y, numbers)

Una tercera opción es escribir una función personalizada. Esta es una buena opción cuando no hay un operador predefinido o la función es demasiado complicada para una lambda. 

Por ejemplo, supongamos que deseas eliminar los duplicados de una lista, pero manteniendo el orden de aparición. Podrías definir un reductor que añada un elemento a una lista solo si no ha aparecido anteriormente.  

from functools import reduce


items = ['the', 'wild', 'wild', 'world', 'is', 'the', 'wide', 'world', 'is', 'the', 'world']


def dedup(acc, x):
    if x not in acc:  # O(n) membership test
        acc.append(x)
    return acc




unique = reduce(dedup, items, [])  # ['the', 'wild', 'world', 'is', 'wide']

Para obtener más ideas sobre cómo eliminar duplicados, consulta este tutorial.

Rendimiento de reduce() en Python

reduce() implica problemas de rendimiento.

Sobrecarga de llamadas a funciones

Python reduce() llama a nuestra función una vez por cada elemento. En una lista con un millón de elementos, esto significa un millón de llamadas a funciones, cada una de las cuales crea un marco, maneja argumentos y actualiza recuentos de referencias. Esto añade una sobrecarga significativa.

Por el contrario, una función integrada como sum realiza una única llamada a una función C y ejecuta el millón de sumas dentro del bucle C. Esta diferencia puede hacer que las órdenes integradas sean mucho más rápidas.

Problemas de localidad de caché y eficiencia de la CPU

Reduce también se ve afectado por la localidad de la caché y la eficiencia de la CPU.  

Una CPU moderna puede ejecutar varios miles de millones de instrucciones por segundo, pero el acceso a la RAM es mucho más lento. Para compensar, las CPU modernas tienencachés de nivel (L1, L2, L3) que almacenan datos para un acceso rápido.

Estas cachés aprovechan dos patrones. 

  • La localidad temporal Los datos utilizados recientemente probablemente se volverán a utilizar. 
  • La localidad espacial cerca de una dirección utilizada recientemente es probable que se utilicen pronto.

Por el contrario, cada paso de reduce() implica la búsqueda de punteros para encontrar el siguiente elemento y llamadas a funciones de Python, lo que rompe la localidad y ralentiza la CPU. Las funciones integradas y vectorizadas evitan este problema ejecutándose en bucles C ajustados.

Para repasar cómo escribir código Python idiomático y eficiente, consulta:

Alternativas a Python reduce()

Elementos empotrados:

  • Código C optimizado. Los componentes integrados ejecutan sus bucles en código C optimizado, no en Python. Esto evita la sobrecarga que supone reduce(). Esta ventaja en cuanto a velocidad se acentúa en entradas grandes. 
  • Legibilidad. Los elementos integrados tienen nombres descriptivos (sum, min), por lo que su finalidad es obvia. Una llamada a reduce() hace que analices la función que se está plegando.

Bucles:

  • Rendimiento. Los bucles suelen ejecutarse más lentamente que las funciones integradas, pero más rápido que reduce().
  • Legibilidad. Al igual que las funciones integradas, los bucles suelen ser más legibles que reduce(). Una llamada a reduce() te obliga a analizar una instrucción funcional, mientras que un bucle es más Python.

itertools.accumulate()

La biblioteca ` itertools ` de Python proporciona una colección de iteradores de alto rendimiento, como ` count()`, ` product()` y ` combinations()`. Una función útil de itertools es itertools.accumulate() . Al igual que reduce(), aplica una función sobre un iterable. Sin embargo, accumulate() almacena valores intermedios del cálculo, no solo el resultado final. 

Por ejemplo,

import itertools, operator
from functools import reduce

list(itertools.accumulate([1, 2, 3, 4], initial=0)) # [0, 1, 3, 6, 10]
reduce(operator.add, [1, 2, 3, 4], 0) # 10

La función Acumular resulta útil cuando necesitas totales acumulados o mínimos/máximos. Por ejemplo, es posible que quieras saber la temperatura máxima mes a mes.

Errores comunes al utilizar reduce()

Cuando utilices reduce(), ten en cuenta los siguientes inconvenientes.

  • Preferir alternativas más sencillas, como los elementos integrados o los bucles. Guarda reduce() para cuando realmente lo necesites.
  • Manejar iterables vacíos. Utiliza siempre un inicializador adecuado para evitar errores en entradas vacías.
  • Problemas de memoria del reloj. No utilices reduce() en situaciones en las que sería más eficiente utilizar un generador o un enfoque de streaming.
  • Evita las lambdas complicadas. Utiliza las funciones del módulo operator siempre que puedas. Las lambdas, especialmente con operaciones no asociativas, pueden perjudicar la claridad.
  • Prefiere la claridad a la inteligencia.

Mejores prácticas y directrices para reduce() en Python 

Al igual que con cualquier herramienta, existen prácticas recomendadas con reduce(). Si has decidido que reduce() es la herramienta adecuada para ti, aquí tienes algunas pautas para su uso.

Diseña primero el reductor. 

  • Define el contrato en una sola frase. «Combinar las claves del diccionario sumando los recuentos por clave».
  • Mantén la asociación si es posible. Esto te permite paralelizar y probar más fácilmente.
  • Identifica tu elemento de identidad y utilízalo como inicializador. Por ejemplo, para la suma, la identidad es 0. Para min, es math.inf, y para set union, es set(). Esto mantiene el código robusto y libre de TypeErrors.

Hazlo sencillo y legible.

  • Una operación clara. Sin efectos secundarios.
  • Asigna un nombre descriptivo al reductor.

Documento

  • En la cadena de documentación, registra el elemento de identidad y el comportamiento de entrada vacía, la suposición de asociatividad y la política de errores.

Prueba

  • Pruebas unitarias en casos extremos: iterables vacíos, tipos mixtos, valores extremos.
  • Prueba la asociatividad.

Supervisar el rendimiento

  • Comparar entradas pequeñas y grandes. Compara los puntos de referencia con los elementos integrados y los bucles.
  • Si la velocidad es importante, considera el preprocesamiento, el procesamiento por lotes y el traslado de cálculos matemáticos pesados a NumPy o pandas.

Aplicaciones avanzadas y casos de uso reales para Python reduce()

Dadas las desventajas, podría parecer que reduce() no tiene ningún valor real. Por el contrario, reduce() tiene muchos casos de uso útiles.

  • Procesamiento de estructuras anidadas
  • Operaciones de tipo base de datos
  • Canales de procesamiento de datos
  • Aplicaciones MapReduce

Procesamiento de estructuras anidadas

Reduce proporciona una forma limpia de recorrer estructuras de datos anidadas, como objetos JSON, plegando una secuencia de claves en búsquedas sucesivas.

import json
from functools import reduce
import operator

data = json.loads('''
{
  "user": {
    "id": "ABC123",
    "name": "Alice",
    "email": "alice@example.com",
    "profile": {
      "address": {
        "city": "San Francisco",
        "zip": "94103"
      },
      "age": 34,
      "skills": ["Python", "Data Science", "Machine Learning"]
    }
  }
}
''')

# Example lookups with reduce + operator.getitem
city = reduce(operator.getitem, ["user", "profile", "address", "city"], data)
print(city)  # "San Francisco"

user_id = reduce(operator.getitem, ["user", "id"], data)
print(user_id)  # "ABC123"

age = reduce(operator.getitem, ["user", "profile", "age"], data)
print(age)  # 34

En este caso, tiene sentido utilizar reduce(). El JSON está profundamente anidado: user → profile → address → city. En lugar de encadenar búsquedas manualmente, representa la ruta como una lista de claves. A continuación, utiliza reduce(operator.getitem, path, data) para recorrerlo. Esto mantiene el código genérico, legible y reutilizable.

Canales de procesamiento de datos

Reduce puede impulsar los procesos de procesamiento de datos pasando los datos por una secuencia de transformaciones. Cada función se encarga de un solo paso, y el proceso es el resultado de aplicarlas en orden. Aquí tienes un proceso de juguete que preprocesa una cadena de texto antes de introducirla en un modelo de PLN. 

from functools import reduce
import re

# Define preprocessing steps
def strip_punctuation(s):
    return re.sub(r"[^\w\s]", "", s)

def to_lower(s):
    return s.lower()

def remove_stopwords(s):
    stops = {"the", "is", "a", "of"}
    return " ".join(word for word in s.split() if word not in stops)

def stem_words(s):
    # trivial "stemmer": cut off 'ing'
    return " ".join(word[:-3] if word.endswith("ing") else word for word in s.split())

pipeline = [
    strip_punctuation,
    to_lower,
    remove_stopwords,
    stem_words,
]

# Input data
text = "The quick brown fox is Jumping over a log."

# Apply pipeline with reduce
processed = reduce(lambda acc, f: f(acc), pipeline, text)
print(processed)  # quick brown fox jump over log

Gestión de errores en aplicaciones complejas

Volvamos al ejemplo de JSON anidado. En este momento, la llamada directa a reduce(operator.getitem, …) lanza una excepción KeyError o TypeError si falta una clave o si encuentra un elemento que no es un diccionario. Para que el código sea más seguro, define una función auxiliar que envuelva operator.getitem en un bloque try/except y devuelva un valor predeterminado cuando se produzca un error.

Aquí tienes una posibilidad para la función auxiliar.

def deep_get(data, keys, default=None):
    """Traverse nested dicts/lists safely with reduce."""
    try:
        return reduce(operator.getitem, keys, data)
    except (KeyError, IndexError, TypeError):
        return default

Ahora, cambia las búsquedas de ejemplo para usar nuestra nueva función en lugar de una sin envolver. reduce()

# Example lookups
city = deep_get(data, ["user", "profile", "address", "city"], default="Unknown City")
print(city)  # "San Francisco"

user_id = deep_get(data, ["user", "id"], default="N/A")
print(user_id)  # "ABC123"

age = deep_get(data, ["user", "profile", "age"], default="N/A")
print(age)  # 34

# Example with missing key
phone = deep_get(data, ["user", "profile", "phone"], default="No phone")
print(phone)  # "No phone"

Transformaciones de datos en varios pasos con map() y filter()

Puedes combinar reduce() con otras herramientas funcionales, como map() y filter(), para crear transformaciones de datos de varios pasos.  Aquí está vuestra canalización de preprocesamiento de PNL anterior escrita de forma funcional.

from functools import reduce
import re

# Define preprocessing steps
def strip_punctuation(s):
    return re.sub(r"[^\w\s]", "", s)

def to_lower(s):
    return " ".join(map(str.lower, s.split()))

def remove_stopwords(s):
    stops = {"the", "is", "a", "of"}
    return " ".join(filter(lambda w: w not in stops, s.split()))

def stem_words(s):
    # trivial "stemmer": cut off 'ing'
    return " ".join(map(lambda w: w[:-3] if w.endswith("ing") else w, s.split()))

# Pipeline of transformations
pipeline = [
    strip_punctuation,
    to_lower,
    remove_stopwords,
    stem_words,
]

# Input data
text = "The quick brown fox is Jumping over a log."

# Apply pipeline with reduce
processed = reduce(lambda acc, f: f(acc), pipeline, text)
print(processed)  # quick brown fox jump over log

Las transformaciones son:

  • Elimina la puntuación. «El rápido zorro marrón está saltando sobre un tronco». → «El rápido zorro marrón está saltando sobre un tronco».
  • Minúscula

«El rápido zorro marrón está saltando sobre un tronco» → «el rápido zorro marrón está saltando sobre un tronco»

  • Eliminar palabras vacías. «El rápido zorro marrón está saltando sobre un tronco» → «rápido zorro marrón saltando sobre tronco».
  • Palabras raíz

 «quick brown fox jumping log» → «quick brown fox jump log»

Para profundizar en las ideas de programación funcional y vectorización, recomendamos estos artículos de DataCamp.

Integración con el ecosistema moderno de Python

Para utilizar bien reduce(), es útil comprender cómo encaja en el ecosistema Python moderno. Profundicemos en cómo encaja junto con NumPy y pandas, cómo sustenta los sistemas paralelos y distribuidos, y cómo interactúa con herramientas modernas como los analizadores estáticos. 

numpy y pandas

NumPy y pandas funcionan a partir de código C optimizado, así que no dupliques su funcionalidad con reduce(). Sin embargo, reduce() es una buena opción para los pipelines con pasos dinámicos. Por ejemplo, puedes componer muchas transformaciones NumPy en un arreglo.

from functools import reduce
import numpy as np

def standardize(x):
    return (x - x.mean()) / (x.std() + 1e-9)

def clip(x):
    return np.clip(x, 0, 1)

def log(x):
    return np.log1p(x)

x = np.array([1, 500, 40.5, 100, 250.45])
funcs = [standardize, clip, log]
y = reduce(lambda a, f: f(a), funcs, x)  # x is ndarray

Marcos de computación paralela y distribuida

La reducción es fundamental en los marcos de computación paralela y distribuida. Estos sistemas funcionan dividiendo un conjunto de datos en particiones, procesando esas particiones en paralelo y combinando luego los resultados parciales en una única respuesta. El paso de «combinar» es la reducción.

Para que la reducción funcione correctamente en un clúster, asegúrate de que se cumplan las siguientes condiciones.

  • Asociatividad. La operación debe dar el mismo resultado independientemente de la agrupación. Esto permite fusionar resultados parciales en cualquier orden a través de la red.
  • Elemento de identidad. La operación debe tener un inicializador que no afecte al resultado final. Esto garantiza la corrección cuando las particiones están vacías o tienen tamaños desiguales. 

Si estas propiedades no se cumplen, las reducciones se vuelven lentas (porque no se pueden paralelizar de forma segura) o incorrectas (porque los resultados dependen del orden de evaluación).

Este proceso requiere una operación asociativa y una identidad clara. De lo contrario, obtendrás un código lento o resultados incorrectos.

Herramientas de análisis estático

Un analizador estático (como mypy, Pyright, ruff o bandit) es una herramienta que inspecciona el código sin ejecutarlo. Estas herramientas detectan errores, aplican reglas de estilo y comprueban la corrección tipográfica.

Los analizadores estáticos tienen dificultades con reduce(). En el proceso de plegado, el tipo de acumulador puede diferir del tipo de elemento, y la inferencia de tipos se vuelve confusa. 

Considera este código.

from functools import reduce

def add_chars(acc, word):
    acc.extend(word)   # extend adds each character of the string
    return acc

chars = reduce(add_chars, ["hi", "ok"], [])
print(chars)  # ['h', 'i', 'o', 'k']

Aunque este código funciona correctamente, un analizador estático podría señalar algunos problemas.

  • El tipo de elemento del inicializador [] es ambiguo. 
  • Los analizadores pueden suponer que los tipos del acumulador y del elemento coinciden.

Para que el código resulte más claro tanto para los humanos como para los analizadores, añade indicaciones de tipo.

from functools import reduce
from typing import List

def add_chars(acc: List[str], word: str) -> List[str]:
    acc.extend(word)   # extend adds each character of the string
    return acc

chars: List[str] = reduce(add_chars, ["hi", "ok"], [])
print(chars)  # ['h', 'i', 'o', 'k']

Ahora el reductor muestra explícitamente

  • El acumulador es un List[str].
  • Cada elemento es un str.
  • El tipo de retorno es un objeto de tipo « list[str] ».

Con estas pistas, los analizadores estáticos pueden comprobar rigurosamente el código. 

Conclusión

Reduce proviene de la programación funcional, donde la idea central es combinar colecciones en un único resultado. Aunque ya no es una herramienta de primera clase en Python, tiene su lugar. Cuando necesitas tuberías flexibles, pliegues personalizados u operaciones que no se ajustan perfectamente a las funciones existentes, reduce() es una herramienta muy potente. Si se utiliza con cuidado, se integra perfectamente en el ecosistema Python más amplio y sigue siendo una herramienta práctica en las situaciones adecuadas.

Algunos enlaces relacionados con Python que pueden resultarte útiles.

Preguntas frecuentes sobre reduce() en Python

¿Qué hace reduce()?

Aplica repetidamente una función de dos argumentos a un iterable para reducirlo a un único resultado.

¿Dónde está definido reduce()?

Antes de la versión 3, era una función integrada. Desde entonces, se encuentra en el módulo functools.

¿Qué tipo de funciones debes pasar a reduce()?

Funciones sencillas, asociativas y bien documentadas. Evita los efectos secundarios y la lógica no asociativa.

¿En qué se diferencia de itertools.accumulate()?

reduce() solo devuelve el resultado final, mientras que accumulate() devuelve todos los resultados intermedios.

¿Cuándo debes usar un inicializador?

Utiliza un inicializador cuando el iterable pueda estar vacío.

Temas

Los mejores cursos de Python

Programa

Fundamentos de Datos en Python

0 min
Desarrolla tus habilidades con los datos, descubre cómo manipularlos y visualizarlos, y aplica análisis avanzados para tomar decisiones basadas en datos.
Ver detallesRight Arrow
Comienza el curso
Ver másRight Arrow
Relacionado

Tutorial

Funciones lambda de Python: Guía para principiantes

Aprende sobre las funciones lambda de Python, su finalidad y cuándo utilizarlas. Incluye ejemplos prácticos y mejores prácticas para una implementación eficaz.
Mark Pedigo's photo

Mark Pedigo

Tutorial

Tutorial de funciones de Python

Un tutorial sobre funciones en Python que cubre cómo escribir funciones, cómo invocarlas y mucho más.
Karlijn Willems's photo

Karlijn Willems

Tutorial

Tutorial sobre la función range() de Python

Aprende sobre la función range() de Python y sus capacidades con la ayuda de ejemplos.
Aditya Sharma's photo

Aditya Sharma

Tutorial

Tutorial de comprensión del diccionario Python

¡Aprende todo sobre la comprensión de diccionarios en Python: cómo puedes utilizarla para crear diccionarios, para sustituir los for loops (anidados) o las funciones lambda por map(), filter() y reduce(), ...!
Sejal Jaiswal's photo

Sejal Jaiswal

Tutorial

Tutorial y ejemplos de funciones y métodos de listas en Python

Aprende sobre las funciones y métodos de las listas de Python. ¡Sigue ahora los ejemplos de código para list() y otras funciones y métodos de Python!
Abid Ali Awan's photo

Abid Ali Awan

Tutorial

Función Print() de Python

Aprenda cómo puede aprovechar la capacidad de una simple función de impresión de Python de varias maneras con la ayuda de ejemplos.
Aditya Sharma's photo

Aditya Sharma

Ver másVer más