# Lambda in Python: le funzioni anonime in Python

Le funzioni lambda esistono sin da Python 1.0 come **mezzo per la programmazione funzionale**. Oggi il loro utilizzo è stato sostituito in larga parte da altre tecniche. Tuttavia vi sono ancora alcuni ambiti specializzati in cui i programmatori Python più esperti dovrebbero saperle utilizzare.

## Che cosa sono le funzioni lambda in Python?

Con il termine **“funzione lambda” in Python si intende una funzione anonima**. Per creare una funzione lambda in Python si utilizza la parola chiave `lambda`. Un’espressione lambda è composta dalla parola chiave `lambda` seguita da un elenco di argomenti, dai due punti e da una singola espressione (“expression”). Richiamando la funzione lambda, l’espressione viene dotata degli argomenti e valutata:

```none
lambda argument: expression
```

Le funzioni sono un costrutto linguistico fondamentale di quasi tutti i linguaggi di programmazione e costituiscono la minima unità di codice riutilizzabile. Di solito le **funzioni in Python sono definite con la parola chiave `def`**. Come esempio, vi mostriamo la funzione di Python che eleva un numero al quadrato moltiplicandolo per sé stesso:

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

Oltre al noto metodo usato per definire le funzioni in Python con la parola chiave `def`, il linguaggio di programmazione dispone anche delle “lambda”. Si tratta di brevi **funzioni anonime (ossia a cui non è stato assegnato un nome) che definiscono un’espressione con dei parametri**. Le lambda si utilizzano in tutti i casi in cui è prevista una funzione oppure si collegano a un nome tramite assegnazione. Questa è l’espressione lambda equivalente alla funzione per elevare al quadrato:

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

N.B. Il termine “funzione lambda” indica in Python una funzione creata con la parola chiave lambda. Lambda non è il nome di una funzione e non si tratta di un [operatore Python](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/operatori-python/ "Operatori Python").

### Qual è la differenza fra lambda e def?

A prima vista può sembrare strano che in Python vi siano due modi per creare le funzioni, ossia con `lambda` e con `def`. In realtà, `lambda` **non è un metodo vero e proprio, ma soltanto una diversa sintassi** con cui scrivere brevi funzioni in locale. Infatti, ogni funzione creata con `lambda` può essere creata anche con `def`. Tuttavia, non è vero il contrario.

A livello sintattico, sia `lambda` che `def` sono parole chiave. Una differenza fra le due funzionalità sta nella **rigorosa distinzione tra istruzione (“statement”) ed espressione (“expression”)** in Python. In poche parole, le istruzioni sono fasi di esecuzione del codice, mentre le espressioni sono valutate per restituire un valore.

La parola chiave `def` indica l’inizio di un’**istruzione (nello specifico, un’“istruzione composta”) che contiene ulteriori istruzioni**. All’interno dell’istruzione `def` (e solo qui) possono esservi delle istruzioni `return`. Richiamando la funzione definita con `def`, un’istruzione `return` restituisce un valore.

A differenza dell’istruzione `def`, la **parola chiave `lambda` indica l’inizio di un’espressione che non può contenere istruzioni**. L’espressione lambda riceve uno o più argomenti e restituisce una funzione anonima. Richiamando la funzione generata con lambda, l’espressione che contiene viene valutata con gli argomenti indicati e quindi restituita.

### Quali sono le limitazioni delle espressioni lambda in Python?

Python limita appositamente l’utilizzo delle funzioni lambda, in quanto di norma **è meglio assegnare un nome alle funzioni**. Questa scelta obbliga i programmatori a riflettere sul significato della funzione e a separare i vari componenti in modo chiaro l’uno dall’altro.

A differenza del corpo di una funzione definita con la parola chiave `def`, le lambda non possono contenere alcuna istruzione. Pertanto **non è impossibile utilizzare `if`, `for` ecc. all’interno di una funzione lambda**. Analogamente, non è possibile sollevare un’eccezione, in quanto per farlo serve l’istruzione `raise`.

Le funzioni lambda in Python possono contenere soltanto una singola espressione, che viene valutata quando viene richiamata. All’interno dell’espressione lambda **non è possibile utilizzare annotazioni di tipo**. Oggi per la maggior parte delle applicazioni delle funzioni lambda in Python si utilizzano altre tecniche. Al riguardo, vale la pena menzionare in particolare le comprensioni.

## Per cosa si utilizzano le funzioni lambda in Python?

In generale, **le lambda provengono dalla programmazione funzionale**. In alcuni linguaggi, come JavaScript, si utilizzano spesso le funzioni anonime senza ricorrere a una particolare parola chiave. In Python, le espressioni lambda servono a creare piccole funzioni in locale senza troppi fronzoli. Nelle parti seguenti vi spieghiamo le loro applicazioni più utili.

### Utilizzo di funzioni di ordine superiore in Python con le lambda

Spesso si utilizzano le lambda in connessione con **funzioni di ordine superiore, come `map()`, `filter()` e `reduce()`**. Grazie alle lambda è possibile trasformare gli elementi di un “iterabile” senza l’uso di cicli. Per funzioni di ordine superiore (in inglese, “higher-order functions”) si intendono funzioni che assumono altre funzioni come parametri oppure che restituiscono una funzione.

La funzione `map()` assume come parametro una funzione e un iterabile ed esegue quindi la funzione per ciascun elemento dell’iterabile. Consideriamo il problema di generare numeri al quadrato: utilizziamo la funzione `map()` e **assegniamo un’espressione lambda come argomento che genera la funzione di elevamento al quadrato**. Con `map()` si applica la funzione di elevamento al quadrato a ogni elemento della lista:

```python
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]
```

N.B. A partire da Python 3.0, le funzioni `map()` e `filter()` restituiscono un iterabile anziché una lista. All’interno dell’istruzione `assert` utilizziamo una chiamata `list()` per spacchettare l’iterabile ottenendo una lista.

Le comprensioni di lista offrono oggi un **approccio moderno e preferibile per l’elaborazione di iterabili**. Anziché ricorrere a `map()` e creare una funzione lambda, è possibile descrivere l’operazione direttamente:

```python
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]
```

Con la funzione `filter()` è possibile **filtrare gli elementi di un iterabile**. Allarghiamo il nostro esempio in modo da generare solo numeri al quadrato pari:

```python
# 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]
```

Qui mostriamo nuovamente l’approccio moderno e preferibile per generare **lo stesso risultato senza uso di lambda e funzioni di ordine superiore** per mezzo delle comprensioni di lista. A tal fine usiamo il componente `if` della comprensione per filtrare i numeri al quadrato pari:

```python
# 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]
```

N.B. La funzione `reduce()` di Python non fa più parte della libreria standard a partire da Python 3.0. Ora si trova nel modulo `functools`.

### Realizzazione di funzioni chiave in Python sotto forma di lambda

Le comprensioni hanno sostituito in larga parte l’uso delle classiche funzioni di ordine superiore `map()` e `filter()` in Python. Con le cosiddette “key functions”, in italiano “funzioni chiave”, esiste comunque uno **scenario applicativo in cui le lambda mostrano tutto il loro potenziale**.

Le funzioni di confronto Python `sorted()`, `min()` e `max()` operano su iterabili. Alla chiamata, **ciascun elemento dell’iterabile viene sottoposto a un confronto**. Le tre funzioni assumono tutte una funzione chiave sotto forma di parametro `key` opzionale. La funzione chiave è chiamata per ciascun elemento e restituisce un valore chiave per l’operazione di confronto.

Come esempio, consideriamo il problema seguente. È presente una cartella contenente file di immagini, i cui nomi sono riportati in una lista di Python. **L’obiettivo è mettere in ordine la lista**. I nomi dei file iniziano tutti per `img`, seguito da una numerazione:

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

Se usiamo la funzione `sorted()` di Python, **si utilizza il cosiddetto “ordine lessicografico”**. In pratica, la funzione gestisce le cifre consecutive come singoli numeri. In tal modo, i numeri `['1', '2', '100']` vengono ordinati come `['1', '100', '2']`. Il risultato non corrisponde alle nostre aspettative:

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

Per ottenere l’ordine desiderato, creiamo un’**espressione `lambda` che genera una funzione chiave**. La funzione chiave estrae la componente numerica di un nome del file, che viene quindi utilizzata da `sorted()` come chiave:

```python
# 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']
```

La funzione chiave viene utilizzata solo in locale e una volta sola. Non è necessario definire appositamente un’ulteriore funzione dotata di nome. **Le lambda sono quindi lo strumento giusto per creare funzioni chiave**. Consideriamo altri due esempi.

Oltre a `sorted()`, le funzioni `min()` e `max()` integrate in Python assumono una funzione chiave opzionale. Le funzioni individuano l’elemento più piccolo e/o più grande in una lista o in un altro iterabile. **Cosa sia esattamente l’elemento più piccolo e/o più grande dipende dalla definizione** ed è quindi definibile per mezzo della funzione chiave.

Nelle liste che contengono valori semplici, ad esempio una lista di numeri, è **chiaro che cosa si intenda per “più piccolo” e “più grande”**. In questo caso non serve alcuna funzione chiave speciale:

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

N.B. Se non si assegna nessuna funzione chiave, si utilizza implicitamente la funzione identità `f(x) = x`. Quest’ultima è facilmente definibile come funzione lambda di Python con `lambda x: x`.

Cosa succede invece se ciascuno degli elementi di un iterabile comprende più dati? Immaginiamo di avere una lista di dict che rappresentano le persone con nome ed età. Quale criterio **devono usare `min()` e `max()` per stabilire qual è l’elemento più piccolo e/o più grande**? La funzione chiave serve proprio a questo.

Per capire meglio **come funzionano le funzioni chiave servono dei dati di esempio**. Creiamo una funzione `Person()` che funge da costruttore:

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

Con questa funzione costruttore **creiamo una lista di persone**:

```python
# Create list of people
people = [Person('Mario', 42), Person('Roberto', 51), Person('Giovanni', 69)]
```

Successivamente troviamo la persona più vecchia per mezzo della chiamata `max()`. A tal fine **usiamo l’espressione lambda per creare una funzione chiave** che elabora un dict di una persona e ne estrae l’età come elemento per il confronto:

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

L’approccio funziona esattamente allo stesso modo anche per la funzione `min()`. In questo caso **definiamo la funzione chiave al di fuori della chiamata `min()`** utilizzando nuovamente un’espressione lambda. Questa soluzione migliora la leggibilità ed è utile quando si utilizza la funzione chiave più volte in locale:

```python
# 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('Mario', 42)
```

### Creazione di “closure” con le lambda in Python

Un ulteriore **utilizzo per le lambda in Python è la definizione delle cosiddette “closure”**. Si tratta di funzioni generate da altre funzioni e che memorizzano un valore. Le “closure” permettono ad esempio di creare famiglie di funzioni simili. Vi mostriamo l’esempio più comune per la creazione di funzioni di potenza.

Le funzioni di potenza assumono un argomento e lo elevano a potenza. Esempi noti sono la funzione di elevamento al quadrato `f(x) = x ^ 2` e la funzione di elevamento al cubo `f(x) = x ^ 3`. Tramite una funzione costruttore è possibile creare funzioni di potenza a piacere sotto forma di “closure”. Utilizziamo un’espressione lambda evitando quindi di definire una funzione interna dotata di un nome:

```python
# 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
```

### Espressioni IIFE (Immediately Invoked Function Expression) con le lambda in Python

Le IIFE (pronuncia: “iffy”) sono un **modello ben noto in JavaScript**. Con questo modello si definisce una funzione anonima, che viene eseguita immediatamente.

Anche se le limitazioni **in Python le rendono poco utili, le lambda sono utilizzabili come IIFE**. È sufficiente mettere l’espressione lambda fra parentesi:

```python
(lambda num: num * num)
```

Un’altra coppia di parentesi deve contenere l’argomento o gli argomenti:

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

Consiglio Per muovere i primi passi, vi consigliamo di consultare il nostro [tutorial su Python](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/tutorial-python/ "Tutorial su Python").


This is a markdown version of: [https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/funzioni-lambda-in-python/](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/funzioni-lambda-in-python/) for AI/LLM consumption.