3.7. Usare le funzioni lambda

Python supporta un'interessante sintassi che vi permette di definire al volo delle piccole funzioni di una sola riga. Derivate dal Lisp, queste funzioni lambda possono essere usate ovunque sia richiesta una funzione.

Esempio 3.21. Introduzione alle funzioni 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 Questa è una funzione lambda equivalente alla funzione f(). Notare la sintassi abbreviata: non ci sono parentesi attorno alla lista degli argomenti e la parola chiave return è mancante (implicita, poiché l'intera funzione può essere solamente composta da una espressione). Inoltre, la funzione lambda non ha nome, ma può essere chiamata attraverso la variabile a cui è stata assegnata.
2 Potete usare anche una funzione lambda senza assegnarla ad una variabile. Non è la cosa più utile del mondo, ma dimostra che una funzione lambda equivale ad una funzione “inline” del linguaggio C.

Per generalizzare, una funzione lambda è una funzione che prende qualunque numero di argomenti (inclusi quelli opzionali) e ritorna il valore di una singola espressione. Le funzioni lambda non possono contenere comandi e neppure possono contenere più di una espressione. Non cercate di metterci dentro troppa roba: se avete bisogno di uno strumento più complesso, definite una funzione normale e fatela lunga quanto volete.

Nota
l'utilizzo o meno delle funzioni lambda è questione di stile. Usarle non è mai necessario; in ogni caso in cui vengono usate è possibile definire una funzione normale e usarla al posto della funzione lambda. Le funzioni lambda sono comode, ad esempio, nei casi in cui si voglia incapsulare codice specifico, non riutilizzato, senza riempire il programma di piccolissime funzioni.

Esempio 3.22. funzioni lambda lambda in apihelper.py

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

Notiamo alcune cose in questo esempio. Primo, stiamo usando la forma più semplice del trucco and-or, il che va bene, perché una funzione lambda è sempre vera in un contesto booleano. Ciò non significa che una funzione lambda non possa ritornare un valore falso. La funzione è sempre vera; è il suo valore di ritorno, il risultato, che può essere qualunque cosa.

Secondo, stiamo usando la funzione split senza argomenti. L'avete già vista usare con 1 o 2 argomenti, ma senza argomenti spezza la stringa sui caratteri di spazio.

Esempio 3.23. split senza argomenti

>>> 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 Questa è una stringa su più linee, definita da caratteri di escape anziché triple virgolette. \n è il ritorno a capo; \t è il carattere tab.
2 split senza argomenti spezza negli spazi vuoti. Così tre spazi, un ritorno a capo e un carattere di tabulazione vengono trattati nello stesso modo.
3 Potete collassare gli spazi dividendo una stringa e riattaccandola con un carattere di spazio come delimitatore. Questo è ciò che fa la funzione help per collassare una stringa di più linee in una linea sola.

Cosa fa quindi la funzione help con queste funzioni lambda, split e trucchi and-or?

Esempio 3.24. Assegnare una funzione a una variabile

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

processFunc adesso è una funzione, ma quale funzione sia dipende dal valore della variabile collapse. Se collapse è vera, processFunc(string) collasserà gli spazi vuoti, altrimenti processFunc(string) ritornerà il suo argomento senza alcuna modifica.

Per fare la stessa cosa in un linguaggio meno robusto, come Visual Basic, dovremmo probabilmente creare una funzione che riceve una stringa e l'argomento collapse, usa un'istruzione if per decidere se collassare gli spazi vuoti o no, quindi ritorna il valore appropriato. Ciò sarebbe inefficiente, perché la funzione dovrebbe gestire ogni possibile caso; ogni volta che viene chiamata, dovrebbe decidere se collassare gli spazi prima di restituire il valore desiderato. In Python, potete prendere questa logica di decisione e portarla fuori dalla funzione, definendo una funzione lambda cucita su misura per fare ciò che volete e soltanto quello. Il sistema è più efficiente, più elegante e meno portato al genere di errore dovuto all'errata disposizione degli argomenti di chiamata.

Ulteriori letture