Desde la versión 1.0 de Python, las funciones lambda se utilizan como medio para la pro­gra­ma­ción funcional. Ac­tua­l­me­n­te, la utilidad de esta función ha sido su­s­ti­tui­da en gran medida por otras técnicas. Sin embargo, aún existen algunas áreas de uso es­pe­cia­les que los pro­gra­ma­do­res expertos de Python deberían conocer.

¿Qué son las funciones lambda de Python?

El término “función lambda” significa función anónima en Python. Para crear una función lambda, Python utiliza la palabra clave lambda. Una expresión lambda consiste en la palabra clave lambda seguida de una lista de ar­gu­me­n­tos, dos puntos y una única expresión (“ex­pre­s­sion”). En cuanto se llama la función lambda, se pro­po­r­cio­na la expresión con los ar­gu­me­n­tos y se evalúa:

lambda argument: expression

Las funciones son una co­n­s­tru­c­ción li­n­güí­s­ti­ca fu­n­da­me­n­tal de casi todos los lenguajes de pro­gra­ma­ción y re­pre­se­n­tan la unidad más pequeña de código re­uti­li­za­ble. No­r­ma­l­me­n­te, las funciones en Python se definen con la palabra clave def. Por ejemplo, este también sería el caso de la función square que mu­l­ti­pli­ca un número por sí mismo:

# Define square function
def square(num):
    return num * num
# Show that it works
assert square(9) == 81
python

Además de la forma más conocida de definir funciones en Python mediante la palabra clave def, el lenguaje reconoce las “lambdas”. Estas son funciones breves y anónimas (es decir, sin nombre) que definen una expresión con pa­rá­me­tros. Puedes utilizar las lambdas en cualquier lugar donde se espere una función o se las pueda vincular a un nombre mediante una asi­g­na­ción. Aquí tienes la expresión lambda equi­va­le­n­te a la función square:

# Create square function
squared = lambda num: num * num
# Show that it works
assert squared(9) == 81
python
Nota

En Python, el término “función lambda“se refiere a una función creada con la palabra clave lambda. Lambda no es el nombre de una función y tampoco es uno de los ope­ra­do­res de Python.

¿Cuál es la di­fe­re­n­cia entre lambda y def?

Al principio parece extraño que Python reconozca dos formas de crear funciones: lambda y def. Pero hay que tener en cuenta que lambda no es una función propia, sino si­m­ple­me­n­te una notación diferente para crear funciones cortas lo­ca­l­me­n­te. Todas las funciones creadas con lambda pueden crearse también mediante def. Sin embargo, no ocurre lo mismo a la inversa.

A nivel si­n­tá­c­ti­co, tanto lambda como def son palabras clave. Una di­fe­re­n­cia entre ambas radica en la estricta se­pa­ra­ción que hace Python entre se­n­te­n­cias (“Statement”) y ex­pre­sio­nes (“Ex­pre­s­sion”). Las se­n­te­n­cias son pasos en la ejecución del código, mientras que las ex­pre­sio­nes se evalúan frente a un valor.

Con def comienza una sentencia (co­n­cre­ta­me­n­te un “Compound Statement”) que contiene más se­n­te­n­cias. Dentro de la sentencia def,y solo allí, pueden aparecer se­n­te­n­cias return. Tras la llamada a la función definida con def, una sentencia return devuelve un valor.

A di­fe­re­n­cia de la sentencia def, lambda inicia una expresión que no debe contener ninguna sentencia. La expresión lambda toma uno o más ar­gu­me­n­tos y devuelve una función anónima. Si se llama a la función lambda generada, se hará una eva­lua­ción de la expresión contenida con los ar­gu­me­n­tos pasados y se devolverá el resultado.

¿Cuáles son las li­mi­ta­cio­nes de las ex­pre­sio­nes lambda de Python?

Python limita es­pe­cí­fi­ca­me­n­te la utilidad de las funciones lambda, ya que suele ser mejor nombrar las funciones. Esto obliga a los pro­gra­ma­do­res a pensar en el sentido de la función y a di­s­ti­n­guir cla­ra­me­n­te unas partes de otras.

A di­fe­re­n­cia del cuerpo de una función definida mediante la palabra clave def, las lambdas no pueden contener se­n­te­n­cias. Por tanto, no es posible utilizar if, for, etc. dentro de una función lambda. Tampoco es posible lanzar una excepción (Exception), ya que para ello se necesita la sentencia raise.

Las funciones lambda en Python solo pueden contener una única expresión que se evalúa después de llamarla. Dentro de la expresión lambda, no puedes utilizar ano­ta­cio­nes de tipo. Hoy en día se utilizan otras técnicas para la mayoría de los casos de uso de las funciones lambda de Python. Es­pe­cia­l­me­n­te en las co­m­pre­n­sio­nes.

¿Para qué sirven las funciones lambda de Python?

Las lambdas surgen de la pro­gra­ma­ción funcional. En algunos lenguajes, como Ja­va­S­cri­pt, a menudo se utilizan funciones anónimas sin una palabra clave especial. En Python, las ex­pre­sio­nes lambda se utilizan para crear pequeñas funciones lo­ca­l­me­n­te, sin grandes co­m­pli­ca­cio­nes. Te mostramos los casos de uso más útiles.

Equipar funciones de orden superior con lambdas en Python

Las lambdas se utilizan a menudo en conexión con funciones de orden superior como map(), filter() y reduce(). Con su ayuda, pueden tra­n­s­fo­r­mar­se los elementos de un “iterable” sin utilizar bucles. Las funciones de orden superior son funciones que toman funciones como pa­rá­me­tros o devuelven una función.

La función map() toma como pa­rá­me­tros una función y un iterable y ejecuta la función para cada elemento del iterable. Considera el problema de generar números cuadrados: uti­li­za­mos la función map() y pasamos como argumento una expresión lambda, que genera la función cuadrado. Con map() se aplica la función cuadrado a cada elemento de la lista:

nums = [3, 5, 7]
# Square numbers using using `map()` and `lambda`
squares = map(lambda num: num ** 2, nums)
# Show that it works
assert list(squares) == [9, 25, 49]
python
Nota

Desde Python 3.0, las funciones map() y filter() devuelven un iterable en lugar de una lista. Puedes usar list() dentro de la sentencia assert para de­s­co­m­pri­mir el iterable en una lista.

Con las co­m­pre­n­sio­nes de listas, ahora existe un enfoque moderno y preferido para procesar iterables. En lugar de recurrir a map() y crear una función lambda, puede de­s­cri­bi­r­se la operación di­re­c­ta­me­n­te:

nums = [3, 5, 7]
# Square numbers using list comprehension
squares = [num ** 2 for num in nums]
# Show that it works
assert squares == [9, 25, 49]
python

Con la función filter() pueden filtrarse los elementos de un iterable. Ampliamos nuestro ejemplo para que solo se generen números cuadrados pares:

# List of numbers 1–4
nums = [1, 2, 3, 4]
# Square each number
squares = list(map(lambda num: num ** 2, nums))
# Filter out the even squares
even_squares = filter(lambda square: square % 2 == 0, squares)
# Show that it works
assert list(even_squares) == [4, 16]
python

Volvemos a mostrar el enfoque moderno y preferido de utilizar la co­m­pre­n­sión de listas para generar el mismo resultado sin utilizar lambdas ni funciones de orden superior. Uti­li­za­mos la parte if de la co­m­pre­n­sión para filtrar los números pares de los números cuadrados:

# List of numbers 1–4 squared
squares = [num ** 2 for num in range(1, 5)]
# Filter out the even squares
even_squares = [square for square in squares if square % 2 == 0]
# Show that it works
assert even_squares == [4, 16]
python
Nota

La función reduce() de Python ya no forma parte de la bi­blio­te­ca estándar desde Python 3.0. Se ha tra­s­la­da­do al módulo functools.

Realizar funciones clave con lambdas en Python

Las co­m­pre­n­sio­nes han su­s­ti­tui­do en gran medida el uso de las clásicas funciones de orden superior map() y filter() en Python. Sin embargo, con las “Key-Functions”, existe un escenario de uso en el que las lambdas muestran ple­na­me­n­te sus puntos fuertes.

Las funciones de co­m­pa­ra­ción de Python sorted(), min() y max() operan sobre iterables. Cuando se llama esta función, se compara cada elemento del iterable. Las tres funciones toman una función clave como parámetro opcional key. La función clave se hace cargo de cada elemento y devuelve un valor clave para la operación de co­m­pa­ra­ción.

Como ejemplo, considera el siguiente problema. Imagina que tienes una carpeta con archivos de imagen cuyos nombres están en una lista de Python. Quieres ordenar la lista. Todos los nombres de archivo empiezan por img, seguido de una nu­me­ra­ción:

# List of image file names
images = ['img1', 'img2', 'img30', 'img3', 'img22', 'img100']
python

Si usas la función sorted() de Python, se utiliza el “orden le­xi­co­grá­fi­co”. Esto significa que los dígitos co­n­se­cu­ti­vos se tratan como números únicos. De esta manera, los números ['1', '2', '100'] se colocan en el orden ['1', '100', '2']. Es decir, el resultado no cumple con las ex­pe­c­ta­ti­vas:

# Sort using lexicographic order
sorted_image = sorted(images)
# Show that it works
assert sorted_image == ['img1', 'img100', 'img2', 'img22', 'img3', 'img30']
python

Para que el orden se adapte a tus ne­ce­si­da­des, usamos una expresión lambda que crea una función clave. Esta permite extraer la parte numérica de un nombre de archivo para que sorted() la utilice como clave:

# Extract numeric component and sort as integers
sorted_image = sorted(images, key=lambda name: int(name[3:]))
# Show that it works
assert sorted_image == ['img1', 'img2', 'img3', 'img22', 'img30', 'img100']
python

La función clave solo se utiliza lo­ca­l­me­n­te y una sola vez. No necesitas definir una función con nombre adicional para ella. Por esto, las lambdas son el medio adecuado para crear funciones clave. Veamos otros dos ejemplos.

Además de sorted(), las funciones in­co­r­po­ra­das de Python min() y max() toman una función clave opcional. Las funciones en­cue­n­tran el elemento más pequeño o más grande de una lista u otro iterable. Qué co­n­s­ti­tu­ye exac­ta­me­n­te el elemento más pequeño o más grande es una cuestión de de­fi­ni­ción y puede es­pe­ci­fi­car­se mediante la función clave.

Con listas de valores simples, por ejemplo una lista de números, está claro lo que se entiende por elemento “más pequeño“ o “más grande”. Aquí no se necesita una función clave especial:

nums = [42, 69, 51, 13]
assert min(nums) == 13
assert max(nums) == 69
python
Nota

Si no se pasa ninguna función clave, se utiliza im­plí­ci­ta­me­n­te la función de identidad f(x) = x. Esta se puede definir fá­ci­l­me­n­te como una lambda de Python con lambda x: x.

Pero ¿qué ocurre si los elementos de un iterable co­m­pre­n­den cada uno varias fechas? Imagina una lista de di­c­cio­na­rios (“dicts”) que re­pre­se­n­tan personas con nombre y edad. ¿Según qué criterio deberían min() y max() decidir qué elemento es el más pequeño o el más grande? Para esto se utiliza exac­ta­me­n­te la función clave.

Para ilustrar cómo funcionan las funciones clave, ne­ce­si­ta­mos datos de ejemplo. Por lo tanto, crea una función Person() que sirve de co­n­s­tru­c­tor:

# Constructor function for dict representing a person
def Person(name, age):
    return {'name': name, 'age': age}
# Check that it works as expected
assert Person('Jim', 42) == {'name': 'Jim', 'age': 42}
python

Con ayuda de la función co­n­s­tru­c­to­ra, crea una lista de personas:

# Create list of people
people = [Person('Jim', 42), Person('Jack', 51), Person('John', 69)]
python

A co­n­ti­nua­ción, busca a la persona de más edad mediante la llamada max(). Una vez que hayas realizado este paso, se genera una función clave mediante una expresión lambda que toma un dict de persona y extrae de él la edad como elemento de co­m­pa­ra­ción:

# Find the oldest person
oldest = max(people, key=lambda person: person['age'])
# Check that it works
assert oldest == Person('John', 69)
python

El pla­n­tea­mie­n­to es exac­ta­me­n­te el mismo para la función min(). Aquí hay que definir la función clave fuera de la llamada min() uti­li­za­n­do, nue­va­me­n­te, una expresión lambda. Esto mejora la le­gi­bi­li­dad y merece la pena si la función clave tiene múltiples usos locales:

# Define key function to compare people by age
by_age = lambda person: person['age']
# Find the youngest person
youngest = min(people, key=by_age)
# Check that it works
assert youngest == Person('Jim', 42)
python

Creación de closures con lambdas de Python

Otro uso de las lambdas de Python es la de­fi­ni­ción de los “closures”, funciones que son creadas por otras funciones y almacenan un valor. Los closures pueden uti­li­zar­se, por ejemplo, para crear familias de funciones similares. A co­n­ti­nua­ción, mostramos el ejemplo habitual: crear funciones de potencia.

Las funciones de potencia toman un argumento y lo ex­po­ne­n­cian. Ejemplos conocidos son la función cuadrada f(x) = x ^ 2 y la función cúbica f(x) = x ^ 3. Mediante una función co­n­s­tru­c­to­ra, se puede generar cualquier función potencia como closure. Utiliza una expresión lambda y te ahorras así la de­fi­ni­ción de una función interna con nombre:

# Define constructor function for power functions
def power(n):
    return lambda num: num ** n
# Create square and cubic functions as closures
square = power(2)
cubic = power(3)
# Show that it works
assert square(10) == 100
assert cubic(10) == 1000
python

Im­me­dia­te­ly Invoked Function Ex­pre­s­sion (IIFE) con lambdas en Python

IIFE, pro­nu­n­cia­do “iffy”, es un patrón conocido en Ja­va­S­cri­pt. Define una función anónima y la ejecuta in­me­dia­ta­me­n­te.

Aunque no son muy útiles en Python debido a su re­s­tri­c­ción de uso, las lambdas pueden uti­li­zar­se como IIFE. Solo se necesitan pa­ré­n­te­sis alrededor de la expresión lambda:

(lambda num: num * num)
python

Adi­cio­na­l­me­n­te, otro par de pa­ré­n­te­sis que contengan el argumento o ar­gu­me­n­tos:

assert (lambda num: num * num)(3) == 9
python
Consejo

Si quieres aprender más sobre Python, te re­co­me­n­da­mos nuestro tutorial de Python.

Ir al menú principal