Corso Python / Leggere e scrivere CSV con DictReader e DictWriter
CSV, cioè Comma Separated Values, rappresenta record e campi in un file di testo. Il modulo csv interpreta separatori e virgolette; dopo la lettura devi comunque validare i campi e convertire i numeri, perché DictReader restituisce normalmente valori testuali.
Leggere CSV senza dividere le righe con split
Un campo tra virgolette può contenere una virgola o perfino una nuova riga. split(",") non interpreta queste regole: il nome lunch, team non deve diventare due colonne diverse. Csv.reader ricostruisce i campi; DictReader usa invece la prima riga come intestazione e associa i campi a nomi di chiave.
La documentazione ufficiale del modulo csv descrive lettori, scrittori e dialetti. Un dialetto riunisce opzioni come separatore e carattere di citazione: un file separato da punto e virgola non diventa automaticamente corretto se lo leggi assumendo virgole.
Apri i file con newline="" e lascia che csv gestisca i fine riga. Per la lettura di un file UTF-8 che può iniziare con una BOM, encoding="utf-8-sig" rimuove quel marcatore iniziale; funziona anche su UTF-8 senza BOM. Non è invece una conversione universale per file prodotti in qualunque codifica.
Scrivere un nome con virgola e calcolare il totale
Salva il programma completo come csv_demo.py, in UTF-8, in una cartella riservata all’esercizio. Il file expenses-demo.csv viene sostituito a ogni esecuzione: conserva altrove eventuali dati da non perdere. Il modulo csv è nella libreria standard, quindi non devi installare dipendenze.
Dal terminale nella cartella della prova, con l’interprete del progetto selezionato, esegui python csv_demo.py. Fuori dall’ambiente virtuale su macOS o Ubuntu usa python3 se è il nome dell’interprete scelto. Il significato delle modalità di apertura è descritto nella guida ai file di testo.
import csv
from pathlib import Path
path = Path("expenses-demo.csv")
with path.open("w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["name", "amount"])
writer.writeheader()
writer.writerows([{ "name": "lunch, team", "amount": 8000}, {"name": "bus", "amount": 2500}])
total = 0
with path.open(encoding="utf-8-sig", newline="") as f:
reader = csv.DictReader(f)
if reader.fieldnames != ["name", "amount"]:
raise ValueError("unexpected header")
for row in reader:
total += int(row["amount"])
print(row["name"])
print("total:", total)
Il risultato previsto è:
lunch, team
bus
total: 10500
Fieldnames stabilisce l’ordine name,amount nella scrittura; writeheader emette l’intestazione e writerows scrive i due dizionari. Nel testo del CSV lunch, team deve essere racchiuso tra virgolette. Rileggendolo con csv.reader, ogni record deve avere due campi e il primo nome deve essere esattamente lunch, team, senza virgolette aggiunte al valore.
La lettura verifica anche l’elenco ordinato delle intestazioni prima di sommare. Il valore 8000 viene scritto a partire da un intero, ma DictReader lo restituisce come stringa: int lo converte esplicitamente. Il totale 10500 non implica una conversione di valuta; somma semplicemente i due importi nelle stesse unità.
Definire regole per numeri e record irregolari
Una stringa vuota, un valore come 8,000 o un importo con suffisso di valuta non passano tutti direttamente a int. Prima di ripulire i dati, scegli quali rappresentazioni accettare e come segnalare quelle rifiutate. Eliminare indiscriminatamente i caratteri non numerici può trasformare un errore in un valore apparentemente valido.
Il programma è un esempio minimo: int accetta anche interi negativi e questo codice non li rifiuta. Se rappresentano spese per cui ammetti soltanto valori non negativi, aggiungi una regola del dominio dopo la conversione. Anche nome vuoto e importi fuori scala richiedono criteri espliciti; il parser CSV non li decide per te.
L’intestazione corretta non garantisce che tutte le righe abbiano il numero giusto di campi. Con le impostazioni predefinite, DictReader raccoglie i campi in eccesso sotto la chiave None e assegna None ai valori mancanti; intestazioni duplicate possono sovrascrivere informazioni nella costruzione del dizionario. Per un’importazione reale verifica unicità dei nomi, campi extra, dati mancanti e formato dei valori prima di usarli. L’esempio non realizza ancora questa validazione completa.
Per indicare la posizione puoi numerare i record con enumerate(reader, start=2), includendo l’intestazione nel conteggio logico. Un campo citato su più righe occupa più righe fisiche: il numero logico non coincide necessariamente con quello nel file. L’attributo reader.line_num conta le righe lette dal lettore; chiarisci quale numero riporti nei messaggi d’errore.
Verificare intestazione, ripetizione ed esportazione
- Esegui l’originale e apri il CSV come testo. Controlla la virgola nel nome racchiuso tra virgolette e rileggi il file con un lettore CSV per verificare i due campi.
- In una copia del programma, cambia amount in cost soltanto nella parte di scrittura, sia in fieldnames sia nelle chiavi dei due dizionari passati a writerows. Lascia invariato il controllo delle intestazioni nella parte di lettura: deve fermarsi con ValueError e il messaggio unexpected header.
- Ripristina il codice originale ed eseguilo due volte. Devono restare due record di dati, perché la modalità w sostituisce il file invece di aggiungere righe.
Non basta modificare il CSV generato e riavviare lo stesso programma per provare un errore: la parte iniziale riscrive il file prima di leggerlo. Se cambi solo fieldnames ma lasci amount nei dizionari da scrivere, DictWriter può segnalare già una chiave inattesa durante la scrittura; è un errore diverso dal controllo dell’intestazione che stiamo confrontando.
CSV è testo e non incorpora una politica per le formule di un foglio elettronico. Un’applicazione destinataria può interpretare valori esterni che iniziano, per esempio, con = come formule. Per esportazioni condivise, stabilisci trattamento testuale e validazione adatti al programma che aprirà il file: racchiudere un campo tra virgolette risolve la sintassi CSV, ma non garantisce da solo come verrà interpretato dal foglio elettronico.




