Introduzione
Le tuple sono strutture dati ordinate e immutabili, ma il loro utilizzo non si limita alla semplice memorizzazione di valori. In un progetto reale, una tupla può rappresentare un piccolo insieme di dati correlati: per esempio le coordinate di un punto, il risultato di una misura o una coppia composta da identificativo e descrizione.
Quando il progetto cresce, però, diventa importante descrivere chiaramente la forma della tupla. Una tupla con tre stringhe, due numeri oppure un numero variabile di elementi comunica informazioni molto diverse. Il modulo typing permette di esprimere queste intenzioni con le tuple tipizzate, migliorando leggibilità, autocompletamento e controllo statico del codice.
In questo tutorial vedremo come usare Tuple e la sintassi moderna con tuple[...] per dichiarare tuple a lunghezza fissa e tuple omogenee a lunghezza variabile. L’esempio sarà una piccola funzione che analizza ordini e restituisce dati strutturati in modo esplicito.
Codice completo
from typing import TypeAlias
# Tupla a lunghezza fissa:
# codice prodotto, quantità, prezzo unitario
RigaOrdine: TypeAlias = tuple[str, int, float]
# Tupla a lunghezza fissa per un riepilogo:
# numero di righe, quantità totale, valore complessivo
Riepilogo: TypeAlias = tuple[int, int, float]
def calcola_riepilogo(righe: list[RigaOrdine]) -> Riepilogo:
"""Calcola alcune statistiche sulle righe di un ordine."""
numero_righe = len(righe)
quantita_totale = sum(quantita for _, quantita, _ in righe)
valore_totale = sum(
quantita * prezzo_unitario
for _, quantita, prezzo_unitario in righe
)
# La tupla restituita ha sempre tre elementi
return numero_righe, quantita_totale, valore_totale
def estrai_codici(righe: list[RigaOrdine]) -> tuple[str, ...]:
"""Restituisce una tupla di codici, con lunghezza variabile."""
return tuple(codice for codice, _, _ in righe)
def formatta_riepilogo(riepilogo: Riepilogo) -> str:
"""Trasforma il riepilogo in un messaggio leggibile."""
numero_righe, quantita_totale, valore_totale = riepilogo
return (
f"Righe: {numero_righe} | "
f"Quantità: {quantita_totale} | "
f"Totale: {valore_totale:.2f} euro"
)
ordine: list[RigaOrdine] = [
("USB-C-001", 2, 8.50),
("TAST-002", 1, 24.90),
("USB-C-001", 3, 8.50),
]
riepilogo = calcola_riepilogo(ordine)
codici = estrai_codici(ordine)
print(formatta_riepilogo(riepilogo))
print("Codici presenti:", codici) Spiegazione
Tuple a lunghezza fissa
La definizione:
RigaOrdine: TypeAlias = tuple[str, int, float] descrive una tupla composta esattamente da tre elementi, in questo ordine:
- una stringa che rappresenta il codice del prodotto;
- un intero che rappresenta la quantità;
- un numero decimale che rappresenta il prezzo unitario.
È importante rispettare sia il numero sia il tipo degli elementi. Una riga come ("USB-C-001", 2, 8.50) è coerente con l’alias, mentre una tupla come (2, "USB-C-001", 8.50) presenta i primi due elementi invertiti.
Il controllo di queste annotazioni viene normalmente eseguito da strumenti come mypy o pyright, non dall’interprete Python durante l’esecuzione. Le annotazioni, quindi, documentano il codice e aiutano a individuare errori prima di avviare il programma.
Tuple a lunghezza variabile
La funzione estrai_codici restituisce questa annotazione:
tuple[str, ...] La virgola e i tre punti indicano una tupla di lunghezza variabile contenente esclusivamente stringhe. Sono quindi validi sia ("A",) sia ("A", "B", "C"). Una tupla come ("A", 10), invece, non rispetta il tipo dichiarato.
Questa distinzione è utile perché una tupla a lunghezza fissa rappresenta una struttura con campi precisi, mentre una tupla omogenea rappresenta generalmente una sequenza di elementi dello stesso tipo.
Alias di tipo e leggibilità
Scrivere più volte tuple[str, int, float] può rendere le firme delle funzioni difficili da leggere. Con TypeAlias si assegna un nome significativo alla struttura:
RigaOrdine: TypeAlias = tuple[str, int, float] Il nome RigaOrdine esprime immediatamente il significato dei dati. Inoltre, se la struttura cambia, è sufficiente modificarla in un solo punto.
Compatibilità tra versioni Python
La sintassi tuple[str, int] è disponibile a partire da Python 3.9. Nei progetti che devono supportare versioni precedenti, si può usare la forma equivalente:
from typing import Tuple
RigaOrdine = Tuple[str, int, float] Nei nuovi progetti è generalmente preferibile la sintassi moderna, più semplice e coerente con gli altri tipi generici integrati nel linguaggio.
Best practice
- Usa tuple tipizzate per strutture brevi e stabili: una tupla è adatta quando la posizione degli elementi è nota e il numero di campi è ridotto.
- Scegli nomi descrittivi per gli alias:
RigaOrdinecomunica più informazioni di un genericoDati. - Indica sempre l’ordine dei campi: la tupla non possiede nomi per gli elementi, quindi la documentazione o l’annotazione diventano fondamentali.
- Non usare tuple troppo lunghe: se una struttura contiene molti campi, considera una classe, un
dataclasso un altro modello più esplicito. - Non confondere immutabilità e contenuto immutabile: una tupla non può cambiare i propri elementi, ma può contenere oggetti modificabili, come liste o dizionari.
- Controlla il codice con un type checker: strumenti come
mypypossono rilevare tipi errati nelle tuple prima dell’esecuzione. - Restituisci tuple coerenti: una funzione dovrebbe mantenere sempre lo stesso numero e tipo di elementi dichiarati.
Riepilogo
Le tuple tipizzate permettono di descrivere con precisione dati compatti e ordinati. La sintassi tuple[str, int, float] rappresenta una tupla a lunghezza fissa con tipi specifici, mentre tuple[str, ...] indica una tupla di lunghezza variabile composta da stringhe.
L’uso di alias come RigaOrdine migliora la leggibilità delle funzioni e riduce la duplicazione delle annotazioni. Questa tecnica è particolarmente utile nelle API interne, nelle funzioni che restituiscono riepiloghi e nei modelli semplici in cui i dati hanno una struttura stabile.
Quando invece il numero di campi aumenta o l’accesso per posizione diventa poco chiaro, è opportuno valutare una struttura con attributi nominati, come una dataclass.
