Introduzione
In Python una funzione lambda è una funzione anonima, cioè una funzione priva di un nome dichiarato con def. La sua sintassi è compatta:
lambda argomenti: espressione Le lambda vengono spesso associate a operazioni brevi e immediate. Tuttavia, un uso molto pratico consiste nel combinarle con le funzioni di ordine superiore, cioè funzioni capaci di ricevere altre funzioni come argomento o di restituirle come risultato.
In questo tutorial realizzeremo un piccolo sistema per calcolare prezzi configurabili. L’obiettivo è creare una funzione generatrice che produca diverse regole di calcolo, ad esempio:
- applicare uno sconto percentuale;
- aggiungere l’IVA;
- arrotondare un importo;
- combinare più regole in una sequenza.
Questo approccio è utile quando il comportamento di un programma deve cambiare in base alla configurazione, senza duplicare molte funzioni quasi identiche.
Codice completo
from functools import reduce
def crea_sconto(percentuale):
"""
Restituisce una lambda che applica uno sconto percentuale.
"""
fattore = 1 - percentuale / 100
return lambda prezzo: prezzo * fattore
def crea_iva(percentuale):
"""
Restituisce una lambda che aggiunge l´IVA a un prezzo.
"""
fattore = 1 + percentuale / 100
return lambda prezzo: prezzo * fattore
def crea_arrotondamento(cifre=2):
"""
Restituisce una lambda che arrotonda un numero.
"""
return lambda valore: round(valore, cifre)
def combina_regole(*regole):
"""
Riceve più funzioni e restituisce una funzione composta.
Le regole vengono applicate nell´ordine ricevuto.
"""
return lambda valore: reduce(
lambda risultato, regola: regola(risultato),
regole,
valore
)
# Creiamo alcune regole configurabili
sconto_10 = crea_sconto(10)
iva_22 = crea_iva(22)
arrotonda_2 = crea_arrotondamento(2)
# Componiamo le regole in una pipeline di calcolo
calcola_prezzo_finale = combina_regole(
sconto_10,
iva_22,
arrotonda_2
)
prezzi = [19.90, 45.50, 120.00]
for prezzo in prezzi:
risultato = calcola_prezzo_finale(prezzo)
print(f"Prezzo iniziale: {prezzo:.2f} euro")
print(f"Prezzo finale: {risultato:.2f} euro")
print("-" * 30)
# Possiamo creare una configurazione completamente diversa
solo_sconto = combina_regole(
crea_sconto(25),
arrotonda_2
)
print(f"Prezzo con sconto del 25%: {solo_sconto(80):.2f} euro") Spiegazione
Creare una funzione con una lambda
La funzione crea_sconto() riceve una percentuale e restituisce una nuova funzione:
def crea_sconto(percentuale):
fattore = 1 - percentuale / 100
return lambda prezzo: prezzo * fattore Se chiamiamo crea_sconto(10), otteniamo una funzione che applica sempre uno sconto del 10%. La variabile fattore viene conservata dalla lambda anche dopo la conclusione di crea_sconto(). Questo comportamento è chiamato closure.
sconto_10 = crea_sconto(10)
print(sconto_10(50))
# Output: 45.0 La lambda non conosce soltanto il parametro prezzo: ricorda anche il valore di fattore creato nel contesto esterno.
Funzioni come dati
In Python le funzioni sono oggetti di prima classe. Possono essere assegnate a variabili, inserite in liste e passate ad altre funzioni.
regole = [
crea_sconto(15),
crea_iva(22),
crea_arrotondamento(2)
] Ogni elemento della lista è una funzione. Questo permette di rappresentare un comportamento come una configurazione modificabile, invece di scrivere molti blocchi if.
Comporre più lambda con reduce()
La funzione combina_regole() riceve un numero variabile di funzioni tramite *regole. La funzione reduce() applica ogni regola al risultato precedente.
lambda risultato, regola: regola(risultato) Il flusso di calcolo può essere immaginato così:
- si parte dal prezzo originale;
- si applica lo sconto;
- si applica l’IVA al nuovo valore;
- si arrotonda il risultato finale.
L’ordine è importante. Applicare prima l’IVA e poi lo sconto può produrre un risultato diverso rispetto all’ordine inverso. Una pipeline di funzioni rende questo ordine esplicito e facilmente modificabile.
Perché usare una lambda in questo scenario?
Le lambda sono adatte perché ogni regola è breve, ha una sola espressione e non richiede una logica complessa. Inoltre, la funzione generatrice può creare regole personalizzate durante l’esecuzione del programma:
sconto_5 = crea_sconto(5)
sconto_30 = crea_sconto(30)
print(sconto_5(100))
print(sconto_30(100)) Lo stesso meccanismo può essere applicato a commissioni, conversioni di unità, tariffe di spedizione, normalizzazione di valori e configurazioni di report.
Best practice
- Usa lambda solo per espressioni semplici. Se servono più istruzioni, variabili temporanee o controlli complessi, preferisci
def. - Scegli nomi descrittivi per le funzioni restituite. Una variabile come
calcola_prezzo_finaleè più leggibile di un nome generico comef. - Documenta le funzioni generatrici. Chi usa
crea_sconto()deve capire cosa produce e quali unità di misura utilizza. - Controlla i valori in ingresso. Una percentuale negativa o superiore a 100 potrebbe essere valida in alcuni casi, ma spesso indica un errore.
- Non abusare di
reduce(). Se la composizione diventa difficile da leggere, un cicloforpuò essere più chiaro. - Considera la precisione monetaria. Per applicazioni finanziarie reali,
floatpuò introdurre piccoli errori di arrotondamento. Valuta il modulodecimal. - Evita lambda troppo lunghe. Una riga compatta non è automaticamente una riga leggibile.
Per esempio, una versione più esplicita di combina_regole() potrebbe essere preferibile in un progetto aziendale:
def combina_regole_chiara(*regole):
def applica_regole(valore):
risultato = valore
for regola in regole:
risultato = regola(risultato)
return risultato
return applica_regole Questa variante produce lo stesso risultato, ma rende immediatamente visibile il ciclo di applicazione.
Riepilogo
Le funzioni lambda non servono soltanto a scrivere funzioni brevi in una singola riga. Usate insieme alle closure e alle funzioni di ordine superiore permettono di creare comportamenti configurabili e componibili.
Nel nostro esempio abbiamo:
- generato funzioni personalizzate con
crea_sconto()ecrea_iva(); - conservato configurazioni all’interno di closure;
- trattato le funzioni come dati;
- composto più regole in una pipeline;
- separato la definizione delle regole dalla loro esecuzione.
Il principio fondamentale è semplice: una lambda è efficace quando esprime un’operazione breve e ben comprensibile. Se la logica cresce, è meglio passare a una funzione nominata con def.
