4.7. Utilización de las funciones lambda

Python admite una interesante sintaxis que permite definir funciones mínimas, de una línea, sobre la marcha. Tomada de Lisp, se trata de las denominadas funciones lambda, que pueden utilizarse en cualquier lugar donde se necesite una función.

Ejemplo 4.20. Presentación de las funciones lambda

>>> def f(x):
...     return x*2
...     
>>> f(3)
6
>>> g = lambda x: x*2  1
>>> g(3)
6
>>> (lambda x: x*2)(3) 2
6
1 Ésta es una función lambda que consigue el mismo efecto que la función anterior. Advierta aquí la sintaxis abreviada: la lista de argumentos no está entre paréntesis, y falta la palabra reservada return (está implícita, ya que la función entera debe ser una única expresión). Igualmente, la función no tiene nombre, pero puede ser llamada mediante la variable a la que se ha asignado.
2 Se puede utilizar una función lambda incluso sin asignarla a una variable. No es lo más útil del mundo, pero sirve para mostrar que una lambda es sólo una función en línea.

En general, una función lambda es una función que toma cualquier número de argumentos (incluso argumentos opcionales) y devuelve el valor de una expresión simple. Las funciones lambda no pueden contener sentencias y tampoco pueden contener más de una expresión. No intente exprimir demasiado una función lambda; si necesita algo más complejo, defina en su lugar una función normal y hágala tan grande como quiera.

nota
Las funciones lambda son una cuestión de estilo. Su uso nunca es necesario. Puede definir una función normal separada y usarla en cualquier sitio en que pueda utilizarse una lambda. Yo las utilizo en lugares donde deseo encapsulación, código no reutilizable que no ensucie mi propio código con un montón de pequeñas funciones de una sola línea.

4.7.1. Funciones lambda en el mundo real

Aquí están las funciones lambda de apihelper.py:

    processFunc = collapse and \
                       (lambda s: " ".join(s.split())) or (lambda s: s)

Observe que aquí usamos la forma simple del truco and-or, lo cual está bien porque una función lambda siempre es verdadera en un contexto booleano (esto no significa que una función lambda no pueda devolver un valor falso; la función es siempre verdadera; su valor de retorno puede ser cualquier cosa).

Adiverta también que estamos usando la función split sin argumentos. Ya ha visto usarla con uno o más argumentos, pero sin argumentos hace la división en los espacios en blanco.

Ejemplo 4.21. split sin argumentos

>>> s = "esto   es\nuna\tprueba"  1
>>> print s
esto   es
una	prueba
>>> print s.split()                       2
['esto', 'es', 'una', 'prueba']
>>> print " ".join(s.split())             3
'esto es una prueba'
1 Ésta es una cadena de varias líneas definida por caracteres de escape en lugar de triples comillas. \n es el retorno de carro; \t es el carácter de tabulación.
2 split sin argumentos divide en los espacios en blanco. De modo que tres espacios, un retorno de carro y un carácter de tabulación son lo mismo.
3 Se puede normalizar el espacio en blanco dividiendo una cadena con split y volviéndola a unir con join y un espacio simple como delimitador. Esto es lo que hace la función info para unificar las cadenas de documentación de varias líneas en una sola.

Entonces, ¿qué hace realmente la función info con estas funciones lambda, con split y con los trucos and-or?

    processFunc = collapse and \
                       (lambda s: " ".join(s.split())) or (lambda s: s)

processFunc es ahora una función, pero qué función en concreto es algo depende del valor de la variable collapse. Si collapse es verdadera, processFunc(cadena) unificará el espacio en blanco; en caso contrario, processFunc(cadena) devolverá su argumento sin cambios.

Para hacer esto con un lenguaje menos robusto, como Visual Basic, probablemente crearía usted una función que tomara una cadena y un argumento collapse utilizando una sentencia if, para decidir si unificar o no el espacio en blanco y devolver después el valor apropiado. Esto sería ineficaz, porque la función tendría que considerar todos los casos posibles; cada vez que fuera invocada tendría que decidir si unificar o no el espacio en blanco antes de devolver el valor deseado. En Python, puede tomarse esta decisión fuera de la función y definir una función lambda adaptada para devolver exactamente (y únicamente) lo que se busca. Esto es más eficaz, más elegante, y menos propenso a esos errores del tipo “Huy, creía que esos argumentos iban al revés”.

Lecturas complementarias sobre funciones lambda