2.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 2.21. 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 Esta 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 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 órdenes, y no pueden contener tampoco 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 larga como quiera.

Nota
Las funciones lambda son una cuestión de estilo. Su uso nunca es necesario. En cualquier lugar en que puedan utilizarse, se puede definir una función normal separada y utilizarla en su lugar. 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.

Ejemplo 2.22. Las funciones lambda en apihelper.py

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

Hay varias cosas que advertir de paso. En primer lugar, estamos utilizando la forma simple del truco and-or, lo cual es válido, porque una función lambda siempre es verdadera en contexto booleano. (Esto no significa que una función lambda no pueda devolver un valor falso. La función siempre es verdadera; su valor de retorno puede ser cualquier cosa).

En segundo lugar, estamos utilizando la función split sin argumentos. Ya se ha visto su uso con uno o dos argumentos, pero sin argumentos divide en los espacios en blanco.

Ejemplo 2.23. split sin argumentos

>>> s = "this   is\na\ttest"  1
>>> print s
this   is
a	test
>>> print s.split()           2
['this', 'is', 'a', 'test']
>>> print " ".join(s.split()) 3
'this is a test'
1 Esta es una cadena de varias líneas, definida por los caracteres de escape en lugar detriples 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 con un espacio simple como delimitador. Esto es lo que hace la función help para unificar las cadenas de documentación de varias líneas en una sola línea.

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

Ejemplo 2.24. Asignación de una función a una variable

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

processFunc es ahora una función, pero qué función sea 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 y utilizara una sentencia if para decidir si unificar o no el espacio en blanco, para 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 se le llamara, 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 «Uy, creía que esos argumentos estaban al revés».

Lecturas complementarias