# Funzioni in Python: def, return, argomenti, *args e **kwargs, lambda e annotazioni di tipo

URL: https://skillaria.top/it/guides/python/funzioni-python

Una funzione in Python è un blocco di codice con un nome, che si dichiara con la parola def, si richiama per nome con le parentesi e restituisce un risultato con return; senza return la funzione restituisce None. Gli argomenti si passano per posizione o per nome, *args raccoglie i valori posizionali in più in una tupla, **kwargs i valori con nome in un dizionario, mentre lambda crea una brevissima funzione anonima da una sola espressione.

Una funzione in Python è un blocco di codice con un nome che si può richiamare quante volte si vuole con dati diversi. Si dichiara con la parola `def`, riceve i valori tramite i parametri e restituisce il risultato con `return`. Le funzioni sono il modo principale per trasformare un lungo script in una serie di passaggi chiari e verificabili.

## Come dichiarare una funzione: def in Python

La dichiarazione di una funzione inizia con `def`, seguono il nome, i parametri tra parentesi e i due punti. Il corpo si scrive con un rientro di quattro spazi: il rientro in Python non è un fatto estetico, ma parte della sintassi.

```
def greet(name):
    """Restituisce un saluto per l'utente."""
    return f"Ciao, {name}!"

print(greet("Anna"))   # Ciao, Anna!
```

La stringa tra triple virgolette subito dopo l'intestazione è la docstring, cioè la documentazione della funzione. La mostra `help(greet)` e i suggerimenti dell'editor. Secondo la convenzione PEP 8 i nomi delle funzioni si scrivono in snake_case: `add_expense`, `get_rate`.

La riga `def greet(name):` si chiama firma della funzione: nome più elenco dei parametri (e le annotazioni, se ci sono). Dalla firma si capisce come chiamare la funzione senza leggerne il corpo.

## Che cosa fa return in Python

`return` termina la funzione e restituisce un valore a chi l'ha chiamata. Il codice che segue un `return` già eseguito non viene più eseguito. Se `return` manca o non ha un valore, la funzione restituisce `None`.

```
def area(w, h):
    w * h          # il risultato viene calcolato e poi buttato via

print(area(3, 4))  # None

def area(w, h):
    return w * h

print(area(3, 4))  # 12
```

Il `return` dimenticato è uno degli errori più frequenti dei principianti: la funzione «funziona», ma restituisce `None`, e l'errore emerge una riga più sotto. Si possono restituire anche più valori: in realtà è una sola tupla, che si scompatta comodamente:

```
def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([4, 1, 9])
print(low, high)   # 1 9
```

Un `return` anticipato aiuta a evitare annidamenti inutili: prima si gestiscono i casi particolari, poi la logica principale.

```
def discount(price, is_member):
    if price  T:
    return xs[0]

type Money = int | float
```

In Python 3.14 (PEP 649) le annotazioni sono diventate pigre: vengono valutate al primo accesso, quindi è possibile far riferimento a una classe dichiarata più sotto senza virgolette, e `from __future__ import annotations` non serve più.

## «Non passato» o «passato come None»: sentinella in 3.15

Il valore predefinito `None` non permette di distinguere «l'argomento non è stato passato» da «è stato passato None di proposito». Per anni il problema è stato risolto con un segnaposto fatto in casa:

```
_MISSING = object()

def get_rate(currency, default=_MISSING):
    rates = {"USD": 90.5}
    if currency in rates:
        return rates[currency]
    if default is _MISSING:
        raise KeyError(currency)
    return default
```

In Python 3.15 è comparsa la funzione integrata `sentinel` (PEP 661): `MISSING = sentinel("MISSING")` crea un marcatore unico con una rappresentazione leggibile, che alla copia resta sé stesso, si serializza con pickle e può comparire in un'annotazione del tipo `float | MISSING`. Nelle versioni precedenti funziona ancora il trucco con `object()`.

## Errori tipici con le funzioni

- **Dimenticato return** — la funzione restituisce `None`.
- **Dimenticate le parentesi** — `print(greet)` stampa l'oggetto funzione, non il risultato della chiamata.
- **Valore predefinito mutabile** — una lista comune a tutte le chiamate.
- **Numero errato di argomenti** — `TypeError: greet() missing 1 required positional argument: 'name'`.
- **Nome uguale a quello di una funzione integrata** — una funzione chiamata `list` o `sum` nasconde quella integrata.

## Conclusioni

Le funzioni in Python si dichiarano con `def`, restituiscono il risultato con `return` e ricevono argomenti per posizione o per nome. `*args` e `**kwargs` danno flessibilità, `/` e `*` il rigore delle chiamate, lambda la brevità per le funzioni usa e getta, e le annotazioni di tipo insieme a mypy intercettano gli errori prima dell'esecuzione. Nel corso di Python questo argomento si affronta in pratica: il tracker delle spese si divide in funzioni con annotazioni, verificate con mypy.

## FAQ

**In che cosa un parametro si differenzia da un argomento?**

Il parametro è il nome nella dichiarazione della funzione, l'argomento è il valore concreto passato alla chiamata. In def greet(name) name è un parametro, in greet("Anna") la stringa "Anna" è un argomento.

**Si può chiamare una funzione prima di averla dichiarata?**

A livello di modulo no: la riga def deve essere eseguita prima della chiamata, altrimenti si ottiene NameError. All'interno di un'altra funzione, invece, si può chiamare una funzione dichiarata più sotto, purché la chiamata avvenga dopo la sua dichiarazione.

**Quanti valori può restituire una funzione?**

Formalmente uno solo, ma quel valore può essere una tupla: return a, b restituisce una tupla di due elementi, che si scompatta con x, y = f().

**Le annotazioni di tipo sono obbligatorie?**

No, Python funziona anche senza. Nel codice letto da altre persone, però, le annotazioni semplificano la manutenzione e permettono a mypy o pyright di trovare gli errori prima dell'esecuzione.

**Si può usare if dentro una lambda?**

Solo un'espressione condizionale: lambda x: "pari" if x % 2 == 0 else "dispari". Istruzioni, cicli e assegnazioni non sono ammessi nella lambda.


---
Source: Skillaria.Top (https://skillaria.top)
