Lambdas en Python: Funciones Anónimas y Programación Funcional

Lambdas Python

¿Qué son las funciones lambda en Python?

Las funciones lambda son funciones anónimas pequeñas y de una sola línea que se definen usando la palabra clave lambda. Son una herramienta poderosa de la programación funcional que te permite crear funciones simples de forma concisa, sin necesidad de usar def.

Piensa en las lambdas como «funciones desechables» que usas para operaciones rápidas y sencillas. Son especialmente útiles cuando necesitas una función simple como argumento para otra función y no quieres definir una función completa con def.

Características clave:

  • Anónimas – No requieren un nombre (aunque puedes asignarlas a variables)
  • Una sola expresión – El cuerpo es una única expresión que se retorna automáticamente
  • Concisas – Reducen código boilerplate para funciones simples
  • Funcionales – Pilar de la programación funcional en Python

Sintaxis de las funciones lambda

La sintaxis de una función lambda es simple y directa:

lambda parameters: expression

Comparación con función regular:

# Traditional function with def
def square(x):
    return x ** 2

# Same function with lambda
square_lambda = lambda x: x ** 2

# Both work the same
print(square(5))         # 25
print(square_lambda(5))  # 25

Anatomía de una lambda

Veamos los componentes:

add = lambda a, b: a + b
#     ^^^^^^ ^^^^  ^^^^^
#       |     |      |
#    keyword  |   expression (implicit return)
#         parameters

Puntos importantes:

  1. No uses paréntesis alrededor de los parámetros (a menos que no haya parámetros)
  2. La expresión se evalúa y retorna automáticamente (no uses return)
  3. Solo puede contener una expresión (no múltiples líneas ni sentencias)

Lambda vs def: ¿Cuándo usar cada una?

Lambda vs def Python - Antes después transformación código funciones ilustración comparativa

Cuándo usar lambda

# Good: simple one-line function
double = lambda x: x * 2

# Good: as argument to another function (very common)
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))

# Good: quick throwaway operations
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))

Cuándo usar def

# Good: multi-line functions
def calculate_final_price(price, discount, tax):
    """Calculate final price with discount and tax"""
    price_with_discount = price * (1 - discount)
    price_with_tax = price_with_discount * (1 + tax)
    return round(price_with_tax, 2)

# Good: functions that need docstrings
def validate_email(email):
    """
    Validates if an email has correct format.

    Args:
        email (str): Email to validate

    Returns:
        bool: True if valid, False otherwise
    """
    return "@" in email and "." in email.split("@")[1]

# Good: reusable functions with descriptive names
def calculate_triangle_area(base, height):
    """Calculate area of a triangle"""
    return (base * height) / 2

Regla general: Si la función es simple y se usa una sola vez (especialmente como argumento), usa lambda. Si es compleja o se reutiliza, usa def.


Ejemplos básicos de lambdas

Lambda sin parámetros

# Lambda that always returns the same value
get_pi = lambda: 3.14159

print(get_pi())  # 3.14159

Lambda con un parámetro

# Check if a number is even
is_even = lambda x: x % 2 == 0

print(is_even(4))   # True
print(is_even(7))   # False

# Convert to uppercase
to_uppercase = lambda text: text.upper()

print(to_uppercase("hello"))  # HELLO

Lambda con múltiples parámetros

# Sum of two numbers
add = lambda a, b: a + b
print(add(5, 3))  # 8

# Calculate rectangle area
rectangle_area = lambda width, height: width * height
print(rectangle_area(5, 10))  # 50

# Three parameters
average = lambda a, b, c: (a + b + c) / 3
print(average(10, 20, 30))  # 20.0

Lambda con condicionales (operador ternario)

# Maximum of two numbers
maximum = lambda a, b: a if a > b else b
print(maximum(10, 5))   # 10
print(maximum(3, 8))    # 8

# Absolute value
abs_value = lambda x: x if x >= 0 else -x
print(abs_value(-5))   # 5
print(abs_value(3))    # 3

# Classify age
classify_age = lambda age: "Adult" if age >= 18 else "Minor"
print(classify_age(25))  # Adult
print(classify_age(15))  # Minor

Lambdas con map()

map() aplica una función a cada elemento de un iterable. Las lambdas son perfectas para esto:

Lambdas usando map en python

Sintaxis de map()

map(function, iterable)
# Returns a map object (iterable)

Ejemplos con map()

# Square each number
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared)  # [1, 4, 9, 16, 25]

# Convert temperatures from Celsius to Fahrenheit
celsius = [0, 10, 20, 30, 40]
fahrenheit = list(map(lambda c: (c * 9/5) + 32, celsius))
print(fahrenheit)  # [32.0, 50.0, 68.0, 86.0, 104.0]

# Process strings
words = ["hello", "world", "python"]
uppercase = list(map(lambda s: s.upper(), words))
print(uppercase)  # ['HELLO', 'WORLD', 'PYTHON']

Map con múltiples iterables

# Add elements from two lists
list1 = [1, 2, 3, 4]
list2 = [10, 20, 30, 40]
sums = list(map(lambda x, y: x + y, list1, list2))
print(sums)  # [11, 22, 33, 44]

# Multiply elements from three lists
a = [1, 2, 3]
b = [2, 3, 4]
c = [10, 10, 10]
results = list(map(lambda x, y, z: x * y * z, a, b, c))
print(results)  # [20, 60, 120]

Lambdas con filter()

filter() crea un nuevo iterable con los elementos que cumplen una condición:

Lambdas en una sola linea

Sintaxis de filter()

filter(boolean_function, iterable)
# Returns a filter object (iterable)

Ejemplos con filter()

# Filter even numbers
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even = list(filter(lambda x: x % 2 == 0, numbers))
print(even)  # [2, 4, 6, 8, 10]

# Filter numbers greater than 5
greater = list(filter(lambda x: x > 5, numbers))
print(greater)  # [6, 7, 8, 9, 10]

# Filter strings by length
words = ["a", "bb", "ccc", "dddd", "ee"]
long_words = list(filter(lambda s: len(s) >= 3, words))
print(long_words)  # ['ccc', 'dddd']

Casos de uso prácticos

# Filter prices in a range
prices = [10, 25, 30, 45, 60, 75, 100]
mid_range = list(filter(lambda p: 20 <= p <= 70, prices))
print(mid_range)  # [25, 30, 45, 60]

# Filter valid emails (basic validation)
emails = ["user@example.com", "invalid", "other@test.com", "malformed@"]
valid_emails = list(filter(lambda e: "@" in e and "." in e, emails))
print(valid_emails)  # ['user@example.com', 'other@test.com']

# Filter products in stock
products = [
    {"name": "A", "stock": 0},
    {"name": "B", "stock": 5},
    {"name": "C", "stock": 0},
    {"name": "D", "stock": 10}
]
available = list(filter(lambda p: p["stock"] > 0, products))
print(available)
# [{'name': 'B', 'stock': 5}, {'name': 'D', 'stock': 10}]

Lambdas con sorted()

sorted() ordena iterables, y las lambdas son perfectas para especificar criterios de ordenación personalizados:

# Sort by string length
words = ["python", "is", "an", "awesome", "language"]
sorted_words = sorted(words, key=lambda s: len(s))
print(sorted_words)  # ['is', 'an', 'python', 'awesome', 'language']

# Sort tuples by second element
pairs = [(1, 5), (3, 2), (2, 8), (4, 1)]
sorted_pairs = sorted(pairs, key=lambda x: x[1])
print(sorted_pairs)  # [(4, 1), (3, 2), (1, 5), (2, 8)]

# Sort dictionaries by value
products = [
    {"name": "A", "price": 50},
    {"name": "B", "price": 30},
    {"name": "C", "price": 80}
]
by_price = sorted(products, key=lambda p: p["price"])
print(by_price)
# [{'name': 'B', 'price': 30}, {'name': 'A', 'price': 50}, {'name': 'C', 'price': 80}]

# Descending order
descending = sorted(words, key=lambda s: len(s), reverse=True)
print(descending)  # ['language', 'awesome', 'python', 'is', 'an']

Ordenación por múltiples criterios

# Sort by length then alphabetically
words = ["zzz", "aa", "bbb", "a", "bb", "zz"]
sorted_words = sorted(words, key=lambda s: (len(s), s))
print(sorted_words)  # ['a', 'aa', 'bb', 'zz', 'bbb', 'zzz']

# Students: sort by grade descending, then by name ascending
students = [
    {"name": "Ana", "grade": 85},
    {"name": "Carlos", "grade": 90},
    {"name": "Beatriz", "grade": 90},
    {"name": "David", "grade": 85}
]
sorted_students = sorted(students, key=lambda s: (-s["grade"], s["name"]))
for student in sorted_students:
    print(f"{student['name']}: {student['grade']}")
# Beatriz: 90
# Carlos: 90
# Ana: 85
# David: 85

Profundiza en programación funcional

En el libro Python a fondo encontrarás patrones avanzados de programación funcional, composición de funciones, currificación y más.

Programacion funcional en python

Ver el libro


Lambdas con reduce()

reduce() (del módulo functools) aplica una función acumulativa a los elementos de un iterable:

from functools import reduce

# Sum all numbers
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda a, b: a + b, numbers)
print(total)  # 15

# Multiply all numbers
product = reduce(lambda a, b: a * b, numbers)
print(product)  # 120

# Find maximum
maximum = reduce(lambda a, b: a if a > b else b, numbers)
print(maximum)  # 5

# Concatenate strings
words = ["Python", " ", "is", " ", "awesome"]
sentence = reduce(lambda a, b: a + b, words)
print(sentence)  # Python is awesome

Reduce con valor inicial

from functools import reduce

# Sum starting from 100
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda a, b: a + b, numbers, 100)
print(total)  # 115 (100 + 15)

# Build dictionary from list of tuples
pairs = [("a", 1), ("b", 2), ("c", 3)]
dictionary = reduce(
    lambda d, pair: {**d, pair[0]: pair[1]},
    pairs,
    {}  # Empty dictionary as initial value
)
print(dictionary)  # {'a': 1, 'b': 2, 'c': 3}

Funciones de orden superior

Las funciones de orden superior son funciones que:

  • Reciben otras funciones como argumentos, o
  • Retornan funciones

Las lambdas son perfectas para trabajar con ellas:

Función que retorna una función

def create_multiplier(n):
    """Returns a function that multiplies by n"""
    return lambda x: x * n

double = create_multiplier(2)
triple = create_multiplier(3)

print(double(10))   # 20
print(triple(10))  # 30

Función que recibe una función

def apply_twice(func, value):
    """Applies a function twice to the same value"""
    return func(func(value))

# Using with lambda
result = apply_twice(lambda x: x + 3, 10)
print(result)  # 16 (10 + 3 + 3)

result2 = apply_twice(lambda x: x * 2, 5)
print(result2)  # 20 (5 * 2 * 2)

Composición de funciones

def compose(f, g):
    """Returns the composition of two functions f(g(x))"""
    return lambda x: f(g(x))

# Create simple functions
add_5 = lambda x: x + 5
multiply_2 = lambda x: x * 2

# Compose: first multiply by 2, then add 5
composed_func = compose(add_5, multiply_2)
print(composed_func(10))  # 25 ((10 * 2) + 5)

# Reverse order
composed_func2 = compose(multiply_2, add_5)
print(composed_func2(10))  # 30 ((10 + 5) * 2)

Casos de uso prácticos

1. Procesamiento de datos

# Process product list
products = [
    {"name": "Laptop", "price": 1000, "discount": 0.1},
    {"name": "Mouse", "price": 25, "discount": 0.05},
    {"name": "Keyboard", "price": 75, "discount": 0.15}
]

# Calculate final prices
final_prices = list(map(
    lambda p: p["price"] * (1 - p["discount"]),
    products
))
print(final_prices)  # [900.0, 23.75, 63.75]

# Filter expensive products (final price > 50)
expensive = list(filter(
    lambda p: p["price"] * (1 - p["discount"]) > 50,
    products
))
print([p["name"] for p in expensive])  # ['Laptop', 'Keyboard']

2. Transformación de datos

# User data
users = [
    {"name": "ana garcia", "age": 25},
    {"name": "carlos lopez", "age": 30},
    {"name": "maria torres", "age": 28}
]

# Normalize names (capitalize)
normalized_users = list(map(
    lambda u: {**u, "name": u["name"].title()},
    users
))
print(normalized_users)
# [{'name': 'Ana Garcia', 'age': 25}, ...]

3. Validaciones rápidas

# List of numbers, check if all are positive
numbers = [1, 5, 10, 3, 8]
all_positive = all(map(lambda x: x > 0, numbers))
print(all_positive)  # True

# Check if any is even
any_even = any(map(lambda x: x % 2 == 0, numbers))
print(any_even)  # True

# Filter and count valid emails
emails = ["user@test.com", "invalid", "other@mail.com"]
valid_count = len(list(filter(
    lambda e: "@" in e and "." in e,
    emails
)))
print(valid_count)  # 2

4. Trabajar con diccionarios

# Invert a dictionary
original = {"a": 1, "b": 2, "c": 3}
inverted = dict(map(lambda item: (item[1], item[0]), original.items()))
print(inverted)  # {1: 'a', 2: 'b', 3: 'c'}

# Filter dictionary by condition
numbers_dict = {"a": 1, "b": 5, "c": 3, "d": 8, "e": 2}
greater_than_3 = dict(filter(lambda item: item[1] > 3, numbers_dict.items()))
print(greater_than_3)  # {'b': 5, 'd': 8}

Limitaciones de las lambdas

No pueden contener sentencias

# This does NOT work - can't use print
lambda x: print(x)  # SyntaxError

# This does NOT work - can't use multiple lines
lambda x:
    y = x * 2
    return y  # SyntaxError

# This DOES work - single expression
lambda x: x * 2

Difíciles de debuguear

# With def - traceback shows the name
def square(x):
    """Calculate square of x"""
    return x ** 2

# With lambda - traceback shows "<lambda>"
square_lambda = lambda x: x ** 2

# If there's an error, it's harder to identify which lambda failed

Legibilidad en lambdas complejas

# Hard to read
result = lambda x: x * 2 if x > 0 else -x * 2 if x < -5 else 0

# Better with def for complex logic
def process(x):
    """Process value based on conditions"""
    if x > 0:
        return x * 2
    elif x < -5:
        return -x * 2
    else:
        return 0

Buenas prácticas con lambdas

1. Mantén las lambdas simples

# Good - simple and clear
double = lambda x: x * 2

# Bad - too complex
complex_func = lambda x, y, z: (x + y) * z if x > 0 else (x - y) / z if y != 0 else 0

2. No asignes lambdas a variables si vas a reutilizar

# Avoid this
square = lambda x: x ** 2

# Better: use def for reusable functions
def square(x):
    """Calculate square of x"""
    return x ** 2

3. Usa lambdas como argumentos

# Excellent use of lambda
numbers = [1, 2, 3, 4, 5]
even = list(filter(lambda x: x % 2 == 0, numbers))

4. Nombra variables descriptivamente

# Unclear
f = lambda x: x > 18

# Better
is_adult = lambda age: age >= 18

Puntos clave para recordar

Las funciones lambda son una herramienta poderosa de Python para escribir código más conciso y funcional:

  1. Sintaxislambda parameters: expression – una sola línea sin return
  2. Anónimas – No requieren nombre, perfectas para uso temporal
  3. Uso ideal – Como argumentos para map(), filter(), sorted(), reduce()
  4. Limitaciones – Solo una expresión, no sentencias ni múltiples líneas
  5. vs def – Usa lambda para funciones simples de una línea, def para todo lo demás
  6. Orden superior – Combínalas con funciones que reciben/retornan funciones
  7. Legibilidad – Si la lambda es compleja, mejor usa def

Pepitas de conocimiento

  • Las lambdas se evalúan en el momento de la llamada, no de la definición
  • Puedes usar lambdas con valores por defecto: lambda x, y=10: x + y
  • map() y filter() retornan iteradores, usa list() para convertir
  • Las lambdas son objetos de primera clase, igual que las funciones def
  • Para debuguear, asigna la lambda a una variable con nombre descriptivo

Próximos pasos

Ahora que dominas las lambdas, es momento de explorar otras herramientas de programación funcional como map(), filter() y reduce() en profundidad.


¿Listo para programación funcional avanzada?

Descubre cómo combinar map, filter y reduce para transformar datos eficientemente:

Map, Filter y Reduce en Python


¿Te resultó útil esta guía de lambdas? Compártela con otros desarrolladores Python.

Para patrones avanzados de programación funcional, decoradores y más, consulta Python a fondo.

Compartir

Deja una respuesta

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

Información básica sobre protección de datos Ver más

  • Responsable: Oscar Ramirez.
  • Finalidad:  Moderar los comentarios.
  • Legitimación:  Por consentimiento del interesado.
  • Destinatarios y encargados de tratamiento: No se ceden o comunican datos a terceros para prestar este servicio. El Titular ha contratado los servicios de alojamiento web a ionos (1&1) que actúa como encargado de tratamiento.
  • Derechos: Acceder, rectificar y suprimir los datos.
  • Información Adicional: Puede consultar la información detallada en la Política de Privacidad.

Publicar un comentario

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para fines de afiliación y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Contiene enlaces a sitios web de terceros con políticas de privacidad ajenas que podrás aceptar o no cuando accedas a ellos. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Ver Política de cookies
Privacidad