Metà ottobre 2026: nelle seconde degli istituti tecnici (e nei licei scienze applicate) a scuola avete finito variabili, if e cicli, e adesso l’insegnante di informatica passa alle strutture dati: liste, tuple, dizionari. La verifica arriva fra cinque e otto settimane, tra fine novembre e metà dicembre, e quasi sempre è un compito scritto in cui bisogna leggere del codice e prevederne l’output, oppure scrivere una piccola funzione a mano. Questo post lo scrivo adesso perché le liste si imparano bene solo scrivendole, e due mesi di tempo bastano per farlo con calma.
Se vi manca la base sui cicli, ripartite da programmazione in Python da zero e da diagrammi di flusso e pseudocodice. Qui do per scontato che for, while e if non vi spaventino.
Perché servono le strutture dati
Con le sole variabili, per tenere sei voti servono sei nomi: v1, v2, v3… e il giorno in cui i voti sono sessanta il programma è ingestibile. Una lista raccoglie i valori sotto un solo nome, in ordine, e permette di ripetere la stessa operazione su tutti con un ciclo. Il resto del capitolo è decidere quale contenitore usare, e quali trappole evitare.
Liste: indici, slicing, metodi
Una lista si scrive fra parentesi quadre. Gli indici partono da zero, e quelli negativi contano dalla fine.
voti = [6, 4, 8, 5, 9, 7]
print(voti[0]) # 6
print(voti[-1]) # 7
print(voti[1:4]) # [4, 8, 5]
print(voti[::2]) # [6, 8, 9]
print(len(voti)) # 6
Lo slicing voti[a:b] prende dall’indice a incluso fino a b escluso: è la regola che costa più punti, perché si dimentica che l’estremo destro non c’è. voti[1:4] ha tre elementi, non quattro. Il terzo numero è il passo: [::2] salta un elemento ogni volta.
I metodi che si usano di più:
append(x)aggiungexin fondo;insert(i, x)inseriscexalla posizionei, spostando gli altri;remove(x)elimina la prima occorrenza del valorex;pop()elimina e restituisce l’ultimo elemento,pop(i)quello in posizionei.
voti.append(10)
voti.insert(0, 3)
print(voti) # [3, 6, 4, 8, 5, 9, 7, 10]
voti.remove(3)
ultimo = voti.pop()
print(ultimo, voti) # 10 [6, 4, 8, 5, 9, 7]
Notate la differenza fra remove (cerco per valore) e pop (cerco per posizione): confonderli è un classico da verifica.
Scorrere una lista e la comprehension semplice
Per scorrere una lista si usa for, senza bisogno degli indici:
somma = 0
for v in voti:
somma += v
print(somma, somma / len(voti), max(voti)) # 39 6.5 9
Quando si costruisce una nuova lista filtrando o trasformando un’altra, Python offre la list comprehension, che è solo una scrittura compatta del ciclo con append:
insufficienti = [v for v in voti if v < 6]
print(insufficienti) # [4, 5]
Si legge: “per ogni v in voti, se v è minore di 6, mettilo nella nuova lista”. Se all’inizio non vi viene naturale, scrivete prima il ciclo esteso e poi riducetelo: all’orale e allo scritto vanno bene entrambe.
Tuple: liste che non si modificano
Una tupla si scrive con le parentesi tonde e funziona come una lista, ma è immutabile: dopo averla creata non puoi cambiare, aggiungere o togliere elementi.
punto = (3, 5)
print(punto[0]) # 3
punto[0] = 1 # TypeError: 'tuple' object does not support item assignment
Si usano per dati che non devono cambiare per costruzione: coordinate, una data (giorno, mese, anno), il valore di ritorno di una funzione che dà due risultati. Se scrivete punto[0] = 1 il programma si ferma con un errore, ed è proprio lo scopo: l’immutabilità vi protegge da modifiche involontarie.
Dizionari: chiave e valore
Un dizionario associa a ogni chiave un valore, e si scrive fra graffe. Non si cerca per posizione ma per chiave.
d = {"a": 1}
print(d.get("z")) # None
print(d.get("z", 0)) # 0
d["z"] # KeyError: 'z'
Accedere con d["z"] a una chiave che non esiste dà KeyError; d.get("z", 0) invece restituisce un valore di riserva, che qui è 0. Per scorrere tutto si usa items(), che restituisce le coppie chiave-valore:
for chiave, valore in d.items():
print(chiave, valore)
Stringhe: cenni
Una stringa si comporta come una lista di caratteri, per l’indicizzazione e lo slicing, ma è immutabile come una tupla. Tutto quello che vale per le liste su indici e fette vale anche qui.
s = "python"
print(s[0], s[-1], s[1:4], s.upper(), len(s)) # p n yth PYTHON 6
Per il lavoro sulle stringhe e sui file, nel post dedicato (stringhe e file in Python) c’è il resto.
Quando usare cosa
| Struttura | Ordine | Modificabile | Si usa per |
|---|---|---|---|
| Lista | sì | sì | sequenze di valori che cambiano (voti, punteggi) |
| Tupla | sì | no | dati fissi (coordinate, date) |
| Dizionario | per chiave | sì | associare un nome a un valore (conteggi, rubriche) |
Regola pratica: se ti serve “l’elemento numero 3” usa una lista; se ti serve “il valore associato a Mario” usa un dizionario.
Esercizio 1: statistiche su una lista
Testo. Data voti = [6, 4, 8, 5, 9, 7], calcolare la media e costruire la lista dei voti insufficienti (minori di 6).
Svolgimento. La somma dei sei numeri è , la media è . Il filtro lascia solo 4 e 5.
voti = [6, 4, 8, 5, 9, 7]
media = sum(voti) / len(voti)
insufficienti = [v for v in voti if v < 6]
print(media) # 6.5
print(insufficienti) # [4, 5]
Per esercitarvi sulla stessa logica con più voci, i problemi di cicli e array del terzo anno sono il passo naturale successivo, e per un ripasso del metodo di lavoro vedete la pagina di informatica.
Errori tipici con le liste
Qui si perdono i punti, e conviene guardarli uno per uno.
Indice fuori range. Una lista di tre elementi ha indici 0, 1, 2. Scrivere lista[3] dà IndexError: list index out of range. Quando un ciclo while o un for con range va oltre, controllate se avete usato <= al posto di <.
Modificare la lista mentre la scorri. È l’errore più subdolo, perché non dà alcun messaggio: il programma gira e dà un risultato sbagliato. Lo vediamo nell’esercizio 2.
Copia contro riferimento. b = a non copia la lista: dà alla stessa lista un secondo nome.
a = [1, 2, 3]
b = a
b.append(4)
print(a) # [1, 2, 3, 4] a è cambiata!
c = a.copy()
c.append(5)
print(a, c) # [1, 2, 3, 4] [1, 2, 3, 4, 5]
Per avere una copia indipendente servono a.copy() oppure a[:].
KeyError. Accedere a una chiave assente con le parentesi quadre. Rimedio: get, oppure un if chiave in dizionario prima.
Esercizio 2: togliere i pari (e il bug che nessuno vede)
Testo. Data numeri = [2, 4, 6, 7, 8, 10], eliminare tutti i numeri pari.
Primo tentativo, sbagliato:
numeri = [2, 4, 6, 7, 8, 10]
for n in numeri:
if n % 2 == 0:
numeri.remove(n)
print(numeri) # [4, 7, 10]
Ci si aspetta [7], invece compaiono 4 e 10. Il motivo: il for scorre la lista tenendo un indice interno. Alla prima iterazione n è 2 (indice 0), che viene rimosso; la lista diventa [4, 6, 7, 8, 10] e l’indice avanza a 1, quindi salta il 4 e arriva al 6. Ogni rimozione fa slittare gli elementi e il ciclo ne salta uno.
Soluzione corretta: non modificare la lista che scorri, ma costruirne una nuova.
numeri = [2, 4, 6, 7, 8, 10]
dispari = [n for n in numeri if n % 2 != 0]
print(dispari) # [7]
Altrimenti si può scorrere una copia, con for n in numeri.copy():. In tutti e due i casi, la lista che il ciclo legge non cambia durante la lettura.
Esercizio 3: contare le parole con un dizionario
Testo. Data la frase "il gatto e il cane e il topo", contare quante volte compare ciascuna parola e stampare quelle che compaiono più di una volta.
Svolgimento. split() spezza la frase in una lista di parole. Per ognuna: se è già chiave del dizionario aumento il contatore, altrimenti la inserisco con valore 1.
frase = "il gatto e il cane e il topo"
freq = {}
for parola in frase.split():
if parola in freq:
freq[parola] += 1
else:
freq[parola] = 1
print(freq)
# {'il': 3, 'gatto': 1, 'e': 2, 'cane': 1, 'topo': 1}
for parola, n in freq.items():
if n > 1:
print(parola, n)
# il 3
# e 2
Con get si accorcia tutto il blocco if/else in una riga: freq[parola] = freq.get(parola, 0) + 1. Il risultato è identico; a un compito va benissimo la versione lunga, se la scrivete correttamente.
Questo schema (il dizionario come contatore) è uno dei più richiesti nelle verifiche, perché mette insieme ciclo, condizione e struttura dati. Imparatelo a memoria nella sua forma con if/else.
Errori che costano punti
- Dimenticare che lo slicing esclude l’estremo destro.
- Partire da 1 invece che da 0 con gli indici.
- Confondere
remove(valore) conpop(posizione), oappendconinsert. - Dimenticare i due punti, oppure l’indentazione, dopo
foreif. - Scrivere
b = apensando di aver copiato. - Modificare una lista dentro il ciclo che la scorre.
- Usare
d[chiave]senza controllare che esista. - Nelle prove su carta, scrivere l’output senza seguire il codice riga per riga: la traccia a mano è sempre la strada sicura.
Come prepararsi nelle prossime settimane
- Settimana 1-2: scrivete a mano, su carta, tutti gli snippet di questo post e prevedete l’output prima di eseguirli. Poi eseguiteli e confrontate.
- Settimana 3-4: riscrivete da soli i tre esercizi senza guardare la soluzione. Cambiate i dati (altri voti, un’altra frase) e verificate di nuovo.
- Settimana 5: fate esercizi misti, per esempio “data una lista di nomi, costruisci un dizionario con la lunghezza di ciascuno”. Se uno schema vi blocca, tornate all’esempio base.
- Ogni volta che il codice dà un errore, leggete il messaggio:
IndexError,KeyError,TypeErrordicono già dove guardare.
Non servono ore al giorno: tre sedute da quaranta minuti a settimana, con il codice scritto a mano, valgono più di una rilettura di tutto il quaderno.
Se volete un confronto su un compito vero, o se un passaggio proprio non si sblocca, scrivetemi dalla pagina contatti: faccio volentieri una diagnosi gratuita sugli esercizi che vi hanno dato.