Parametri Avanzati e Funzioni Lambda

Scopri come gestire parametri variabili e creare funzioni anonime con Python

Argomenti Posizionali Variabili (*args)

Gli argomenti variabili vengono usati quando non sappiamo quante variabili passeranno alla funzione.
Si utilizza *args per raccogliere tutti gli argomenti posizionali in una tupla.

Esempio: Somma di N numeri
def somma(*numeri):
    """Restituisce la somma di tutti i numeri passati come argomenti."""
    # args è trattato come una tupla, quindi possiamo iterarci sopra
    return sum(numeri)

# Chiamata della funzione con 3 numeri
print(somma(1, 2, 3))  # Output: 6

# Chiamata della funzione con 4 numeri
print(somma(10, 20, 30, 40))  # Output: 100

Spiegazione:

  • *numeri raccoglie gli argomenti passati alla funzione e li mette in una tupla
  • La funzione sum() somma tutti gli elementi della tupla
  • Possiamo passare qualsiasi numero di argomenti alla funzione


Argomenti Nominativi Variabili (**kwargs)

Quando vogliamo passare un numero arbitrario di coppie chiave-valore alla funzione, usiamo **kwargs.
kwargs sarà trattato come un dizionario.

Esempio: Creazione di un profilo utente
def profilo_utente(**info):
    """Restituisce le informazioni di un utente sotto forma di dizionario."""
    # kwargs è trattato come un dizionario, quindi possiamo accedere ai valori tramite le chiavi
    return info

# Chiamata della funzione con diverse informazioni
print(profilo_utente(nome="Luca", età=25, città="Roma"))
# Output: {'nome': 'Luca', 'età': 25, 'città': 'Roma'}

Spiegazione:

  • **info raccoglie tutte le coppie chiave-valore passate alla funzione
  • Le informazioni vengono memorizzate in un dizionario
  • Possiamo accedere facilmente ai valori tramite le chiavi


Uso Combinato di *args e **kwargs

Possiamo usare sia *args che **kwargs nella stessa funzione.
È importante rispettare l’ordine: prima i parametri posizionali, poi *args,
quindi i parametri con valore di default, e infine **kwargs.

Esempio: Ristorante che accetta piatti e richieste speciali
def ordine_ristorante(cliente, *piatti, servizio="standard", **extra):
    """Restituisce un riepilogo dell'ordine."""
    return {
        "Cliente": cliente,
        "Piatti ordinati": piatti,
        "Servizio": servizio,
        "Extra": extra
    }

# Chiamata della funzione con vari parametri
ordine = ordine_ristorante("Marco", "Pizza", "Pasta", servizio="VIP", bibita="Acqua", dolce="Tiramisù")
print(ordine)

Output
{
    'Cliente': 'Marco',
    'Piatti ordinati': ('Pizza', 'Pasta'),
    'Servizio': 'VIP',
    'Extra': {'bibita': 'Acqua', 'dolce': 'Tiramisù'}
}

Spiegazione:

  • cliente è un parametro posizionale obbligatorio
  • *piatti raccoglie tutti i piatti ordinati in una tupla
  • servizio è un parametro con valore di default che può essere sovrascritto
  • **extra raccoglie tutte le coppie chiave-valore extra in un dizionario


Funzioni Lambda (Anonime)

Le funzioni lambda sono utili per scrivere funzioni rapide e compatte, senza la necessità di dichiararle esplicitamente.

Sintassi di una funzione lambda:

lambda parametri: espressione

1 Esempio: Quadrato di un numero

quadrato = lambda x: x ** 2
print(quadrato(4))  # Output: 16

La funzione lambda prende un parametro x e restituisce il suo quadrato.

2 Ordinare una lista di dizionari

studenti = [
    {"nome": "Anna", "voto": 88},
    {"nome": "Luca", "voto": 95},
    {"nome": "Marco", "voto": 78}
]

# Ordinamento usando una lambda come chiave
studenti_ordinati = sorted(studenti, key=lambda studente: studente["voto"], reverse=True)
print(studenti_ordinati)

Output
[
    {"nome": "Luca", "voto": 95},
    {"nome": "Anna", "voto": 88},
    {"nome": "Marco", "voto": 78}
]

lambda studente: studente["voto"] restituisce il voto per ogni studente, usato per l’ordinamento.

3 Filtro con filter()

numeri = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# Filtro dei numeri pari usando una lambda
numeri_pari = list(filter(lambda x: x % 2 == 0, numeri))
print(numeri_pari)  # Output: [2, 4, 6, 8, 10]

lambda x: x % 2 == 0 verifica se un numero è pari, filter() applica questa condizione a tutti gli elementi.


Esercitazione Guidata: Calcolatore di Stipendio

Obiettivo: Scrivere una funzione che calcoli lo stipendio netto sottraendo le tasse e aggiungendo eventuali bonus.

Soluzione
def calcola_stipendio(base, *bonus, tasse=0.2, **extra):
    """Calcola lo stipendio netto sottraendo le tasse e aggiungendo i bonus"""
    # Somma dei bonus
    totale_bonus = sum(bonus)
    
    # Calcolo dello stipendio lordo
    stipendio_lordo = base + totale_bonus
    
    # Calcolo delle detrazioni
    detrazioni = extra.get("detrazioni", 0)
    
    # Calcolo delle tasse
    tasse_dovute = stipendio_lordo * tasse
    
    # Calcolo dello stipendio netto
    stipendio_netto = stipendio_lordo - tasse_dovute - detrazioni
    return stipendio_netto

# Esempio di utilizzo
stipendio = calcola_stipendio(2000, 300, 150, tasse=0.2, detrazioni=50)
print(stipendio)  # Output: 2290.0

Spiegazione:

  • base è lo stipendio base (parametro posizionale)
  • *bonus raccoglie i bonus aggiuntivi (args)
  • tasse è una percentuale predefinita ma modificabile (parametro default)
  • **extra raccoglie altre informazioni come detrazioni (kwargs)


10 Tracce di Esercizi con Soluzioni

1 Trova il massimo tra numeri variabili

Soluzione
def trova_massimo(*numeri):
    """Restituisce il numero più grande tra quelli passati"""
    return max(numeri) if numeri else None

Spiegazione: Usa max(numeri) per trovare il valore massimo tra i numeri passati come argomenti.
Se numeri è vuoto, restituisce None.

2 Somma i valori di un dizionario

Soluzione
def somma_valori(**kwargs):
    """Somma tutti i valori numerici passati come parametri"""
    return sum(kwargs.values())

Spiegazione: Usa kwargs.values() per ottenere tutti i valori passati come coppie chiave-valore,
quindi usa sum() per sommarli.

3 Ordinare una lista di parole per lunghezza

Soluzione
def ordina_parole(*parole):
    """Restituisce una lista di parole ordinate per lunghezza"""
    return sorted(parole, key=len)

Spiegazione: Usa sorted(parole, key=len) per ordinare le parole in base alla loro lunghezza.
len è una funzione built-in che restituisce la lunghezza di una stringa.

4 Controlla se una parola è un anagramma

Soluzione
def is_anagramma(parola1, parola2):
    """Restituisce True se le due parole sono anagrammi"""
    return sorted(parola1) == sorted(parola2)

Spiegazione: Usa sorted(parola1) e sorted(parola2) per ordinare le lettere di entrambe le parole e confrontarle.
Se le lettere ordinate sono uguali, le parole sono anagrammi.

5 Unisci Dizionari

Soluzione
def unisci_dizionari(**dicts):
    """Combina più dizionari passati come parametri in un unico dizionario"""
    risultato = {}
    for d in dicts.values():
        risultato.update(d)
    return risultato

# Esempio di utilizzo
diz1 = {"a": 1, "b": 2}
diz2 = {"c": 3, "d": 4}
print(unisci_dizionari(d1=diz1, d2=diz2))
# Output: {'a': 1, 'b': 2, 'c': 3, 'd': 4}

Spiegazione: La funzione accetta dizionari come parametri nominativi.
dicts.values() restituisce tutti i dizionari passati, e update() li unisce in un unico dizionario.

6 Filtra Numeri

Soluzione
def filtra_numeri(*numeri, soglia=50):
    """Filtra i numeri maggiori di una soglia specificata"""
    return [n for n in numeri if n > soglia]

# Esempi di utilizzo
print(filtra_numeri(10, 60, 30, 80, 45))  # Output: [60, 80]
print(filtra_numeri(10, 20, 30, soglia=25))  # Output: [30]

Spiegazione: *numeri raccoglie tutti i numeri passati, mentre soglia è un parametro con valore di default.
La list comprehension filtra solo i numeri maggiori della soglia.

7 Calcola Media

Soluzione
def calcola_media(*numeri):
    """Calcola la media aritmetica di numeri variabili"""
    return sum(numeri) / len(numeri) if numeri else 0

# Esempi di utilizzo
print(calcola_media(10, 20, 30))  # Output: 20.0
print(calcola_media(5, 15, 25, 35))  # Output: 20.0
print(calcola_media())  # Output: 0

Spiegazione: *numeri raccoglie tutti i numeri in una tupla.
sum(numeri) calcola la somma, len(numeri) conta quanti sono.
Se non ci sono numeri, restituisce 0 per evitare divisione per zero.

8 Crea Profilo

Soluzione
def crea_profilo(nome, **info):
    """Crea un profilo utente con nome e informazioni aggiuntive"""
    return {"nome": nome, **info}

# Esempi di utilizzo
profilo1 = crea_profilo("Marco", età=30, città="Roma", lavoro="Sviluppatore")
profilo2 = crea_profilo("Anna", email="anna@email.com", telefono="123456789")

print(profilo1)
# Output: {'nome': 'Marco', 'età': 30, 'città': 'Roma', 'lavoro': 'Sviluppatore'}

Spiegazione: nome è un parametro posizionale obbligatorio, mentre **info raccoglie tutte le informazioni aggiuntive.
L’operatore ** “spacchetta” il dizionario direttamente nel nuovo dizionario.

9 Conta Parametri

Soluzione
def conta_parametri(*args, **kwargs):
    """Conta il numero totale di parametri passati alla funzione"""
    return len(args) + len(kwargs)

# Esempi di utilizzo
print(conta_parametri(1, 2, 3))  # Output: 3
print(conta_parametri(1, 2, nome="Marco", età=25))  # Output: 4
print(conta_parametri())  # Output: 0

Spiegazione: len(args) conta gli argomenti posizionali, len(kwargs) conta gli argomenti nominativi.
La somma restituisce il numero totale di parametri passati.

10 Moltiplica con Lambda

Soluzione
# Definizione della funzione lambda
moltiplica = lambda x, y: x * y

# Esempi di utilizzo
print(moltiplica(4, 5))    # Output: 20
print(moltiplica(3, 7))    # Output: 21
print(moltiplica(10, 2.5)) # Output: 25.0

# Utilizzo in combinazione con altre funzioni
numeri = [(2, 3), (4, 5), (6, 7)]
risultati = list(map(lambda coppia: moltiplica(coppia[0], coppia[1]), numeri))
print(risultati)  # Output: [6, 20, 42]

Spiegazione: Le funzioni lambda sono funzioni anonime definite con la sintassi lambda parametri: espressione.
Sono utili per operazioni semplici e rapide. In questo caso, la lambda moltiplica due numeri.

Torna in alto