File CSV in Python
Impara a leggere e scrivere file CSV in Python con il modulo csv integrato: csv.reader, csv.writer, DictReader e DictWriter con esempi pratici.
CSV (Comma-Separated Values) è uno dei formati più comuni per lo scambio di dati tabulari — ogni applicazione per fogli di calcolo, database e strumento di data science è in grado di leggerlo e scriverlo. Il modulo csv integrato in Python gestisce automaticamente le parti complesse: la quotatura dei campi che contengono virgole, la gestione dei caratteri di nuova riga tra i diversi sistemi operativi e la mappatura delle righe in dizionari. Non è necessario installare nulla; csv è incluso in ogni installazione Python.
Questo capitolo tratta la lettura di file CSV, la scrittura di file CSV, l'utilizzo di DictReader e DictWriter, la gestione di delimitatori personalizzati e i problemi comuni da evitare.
Cos'è un File CSV?
Un file CSV è un file di testo normale in cui ogni riga rappresenta una riga di dati e ogni campo all'interno di una riga è separato da un delimitatore — solitamente una virgola. Ecco un esempio minimale:
name,age,city
Alice,30,New York
Bob,25,LondonLa prima riga è tipicamente un'intestazione che assegna un nome a ogni colonna. Le righe successive contengono i dati effettivi. Se il valore di un campo contiene a sua volta una virgola, il campo viene racchiuso tra virgolette doppie:
name,bio
Alice,"Engineer, New York"Il modulo csv gestisce questa quotatura in modo trasparente, quindi non è necessario analizzarla manualmente.
Lettura di File CSV con csv.reader
csv.reader trasforma un file aperto (o qualsiasi iterabile di stringhe) in un iteratore che restituisce ogni riga come lista Python.
Schema di base — lettura di un file CSV riga per riga
import csv
with open("people.csv", newline="") as f:
reader = csv.reader(f)
for row in reader:
print(row)L'argomento newline="" è importante. Senza di esso, la traduzione universale dei caratteri di nuova riga di Python può inserire righe vuote aggiuntive su Windows, poiché il modulo csv gestisce internamente la traduzione dei caratteri di nuova riga.
Supponendo che people.csv contenga i dati dell'esempio precedente, l'output è:
['name', 'age', 'city']
['Alice', '30', 'New York']
['Bob', '25', 'London']Si noti che tutti i valori — incluso il numero 30 — vengono restituiti come stringhe. Il modulo csv non deduce i tipi di dato; è necessario convertirli manualmente quando occorre.
Saltare la Riga di Intestazione
Quando si vogliono solo le righe di dati e non l'intestazione, si chiama next() sul reader una volta per consumare la prima riga:
Saltare la riga di intestazione con next()
import csv
with open("people.csv", newline="") as f:
reader = csv.reader(f)
header = next(reader) # consume and store the header
print("Columns:", header)
for row in reader: # only data rows remain
name, age, city = row
print(f"{name} is {age} years old and lives in {city}.")Output:
Columns: ['name', 'age', 'city']
Alice is 30 years old and lives in New York.
Bob is 25 years old and lives in London.Caricare Tutte le Righe in una Lista
Se si ha bisogno dell'intero file in memoria in una volta sola, si passa il reader a list():
import csv
with open("people.csv", newline="") as f:
reader = csv.reader(f)
rows = list(reader)
print(rows[0]) # header row
print(rows[1]) # first data rowOutput:
['name', 'age', 'city']
['Alice', '30', 'New York']Scrittura di File CSV con csv.writer
csv.writer scrive righe su qualsiasi oggetto simile a un file, quotando automaticamente i campi che contengono il delimitatore, virgolette doppie o caratteri di nuova riga.
Scrittura di righe in un nuovo file CSV
import csv
rows = [
["product", "price", "quantity"],
["Apple", 1.2, 50],
["Banana", 0.5, 100],
["Cherry", 3.0, 30],
]
with open("inventory.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerows(rows)Dopo l'esecuzione, inventory.csv contiene:
product,price,quantity
Apple,1.2,50
Banana,0.5,100
Cherry,3.0,30Si usa writer.writerow(row) per scrivere una singola riga, oppure writer.writerows(rows) per scriverne molte in una volta. Entrambi accettano qualsiasi iterabile.
Perché newline="" è Importante in Scrittura
Su Windows, Python apre i file di testo in una modalità che traduce \n in \r\n. Il modulo csv scrive anche \r\n come terminatore di riga per impostazione predefinita. Insieme producono \r\r\n — una riga vuota tra ogni riga quando il file viene aperto in un altro programma. Passare newline="" sopprime la traduzione aggiuntiva e lascia che csv gestisca autonomamente i terminatori di riga.
Lettura di File CSV con csv.DictReader
DictReader mappa ogni riga in un OrderedDict (o dict semplice in Python 3.8+) con chiavi corrispondenti ai nomi delle colonne nella riga di intestazione. Questo è l'approccio preferito quando le colonne hanno nomi significativi e si vuole accedervi per nome anziché per indice.
Lettura di un file CSV come sequenza di dizionari
import csv
with open("people.csv", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], "—", row["city"])Output:
Alice — New York
Bob — LondonDictReader legge automaticamente la prima riga come intestazione. È possibile sovrascrivere questo comportamento passando un argomento fieldnames:
import csv
# File has no header; provide field names explicitly
with open("data_no_header.csv", newline="") as f:
reader = csv.DictReader(f, fieldnames=["name", "age", "city"])
for row in reader:
print(row)L'attributo reader.fieldnames contiene sempre la lista dei nomi delle colonne in uso, utile per l'ispezione prima di elaborare le righe.
Scrittura di File CSV con csv.DictWriter
DictWriter è il corrispondente di DictReader. Si forniscono i nomi delle colonne in anticipo, poi si scrivono dizionari — il writer mappa ogni chiave nella colonna corretta.
Scrittura di una lista di dizionari in un file CSV
import csv
people = [
{"name": "Alice", "age": 30, "city": "New York"},
{"name": "Bob", "age": 25, "city": "London"},
]
fieldnames = ["name", "age", "city"]
with open("people_out.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader() # writes the column-name row
writer.writerows(people)Il file risultante:
name,age,city
Alice,30,New York
Bob,25,Londonwriteheader() utilizza la lista fieldnames fornita durante la costruzione. Va chiamato una sola volta prima di qualsiasi chiamata a writerow().
Gestione di Chiavi Extra o Mancanti
Per impostazione predefinita, DictWriter lancia un ValueError se un dizionario contiene una chiave non presente in fieldnames. È possibile modificare questo comportamento con il parametro extrasaction:
writer = csv.DictWriter(f, fieldnames=fieldnames, extrasaction="ignore")Viceversa, se un dizionario non ha una chiave, il writer scrive una stringa vuota per quel campo, a meno che non si fornisca un valore predefinito con restval:
writer = csv.DictWriter(f, fieldnames=fieldnames, restval="N/A")Delimitatori e Quotatura Personalizzati
I file CSV reali non sono sempre delimitati da virgole. I file con valori separati da tabulazione (TSV) e i file delimitati da pipe sono comuni. Usare il parametro delimiter per gestirli:
Lettura di un file separato da tabulazioni
import csv
with open("scores.tsv", newline="") as f:
reader = csv.reader(f, delimiter="\t")
for row in reader:
print(row)Scrittura di un file delimitato da pipe
import csv
with open("output.psv", "w", newline="") as f:
writer = csv.writer(f, delimiter="|")
writer.writerow(["id", "name", "score"])
writer.writerow([1, "Alice", 98])
writer.writerow([2, "Bob", 87])File di output:
id|name|score
1|Alice|98
2|Bob|87Costanti di Quotatura
Il parametro quoting controlla quali campi vengono quotati nell'output:
| Costante | Valore | Comportamento |
|---|---|---|
csv.QUOTE_MINIMAL | 0 | Quota solo i campi che contengono il delimitatore, il carattere di quotatura o un carattere di nuova riga (predefinito) |
csv.QUOTE_ALL | 1 | Quota ogni campo |
csv.QUOTE_NONNUMERIC | 2 | Quota tutti i campi non numerici; il reader converte i campi non quotati in float |
csv.QUOTE_NONE | 3 | Non quota mai; genera un errore se il delimitatore compare in un campo |
Forza la quotatura di ogni campo
import csv, io
output = io.StringIO()
writer = csv.writer(output, quoting=csv.QUOTE_ALL)
writer.writerow(["name", "bio"])
writer.writerow(["Alice", "Engineer, New York"])
print(output.getvalue())Output:
"name","bio"
"Alice","Engineer, New York"Uso di io.StringIO per CSV in Memoria
Quando non è necessario accedere al filesystem — ad esempio nei test o quando si elaborano dati CSV ricevuti da un API — si usa io.StringIO come oggetto simile a un file:
Analisi di CSV da una stringa
import csv
import io
raw = "name,score\nAlice,95\nBob,87\n"
reader = csv.DictReader(io.StringIO(raw))
for row in reader:
print(row["name"], "scored", row["score"])Output:
Alice scored 95
Bob scored 87Problemi Comuni
Tutti i Valori Sono Stringhe
csv.reader e DictReader restituiscono sempre stringhe. Convertire i valori esplicitamente:
age = int(row["age"])
price = float(row["price"])Problemi di Codifica
Aprire i file con la codifica corretta per evitare UnicodeDecodeError. UTF-8 è la codifica più comune per i file CSV moderni, ma i file esportati da Excel possono usare latin-1 o cp1252:
with open("data.csv", newline="", encoding="utf-8") as f:
reader = csv.reader(f)Righe Vuote
Se il file CSV contiene righe vuote tra le righe di dati, csv.reader restituisce liste vuote [] per esse. Filtrarle:
import csv
with open("data.csv", newline="") as f:
reader = csv.reader(f)
for row in reader:
if not row: # skip blank lines
continue
print(row)Gestione degli Errori
Racchiudere le operazioni sui file in un blocco try/except per gestire correttamente i file mancanti e gli errori di permesso:
import csv
try:
with open("data.csv", newline="") as f:
reader = csv.reader(f)
for row in reader:
print(row)
except FileNotFoundError:
print("Error: data.csv was not found.")
except PermissionError:
print("Error: no permission to read data.csv.")csv vs Pandas per File di Grandi Dimensioni
Il modulo csv è ideale per:
- File di piccole e medie dimensioni (fino a qualche centinaio di MB)
- Script che non hanno Pandas installato
- Situazioni in cui si necessita di un controllo preciso sulla lettura e scrittura
Per dataset di grandi dimensioni, filtraggio complesso o operazioni di aggregazione, la libreria di terze parti pandas fornisce pd.read_csv() e DataFrame.to_csv(), che sono significativamente più veloci e ricche di funzionalità.
Mettere Tutto Insieme
L'esempio seguente legge un file CSV, filtra le righe in base a una condizione e scrive i risultati filtrati in un nuovo file:
Filtrare le righe e scrivere un nuovo file CSV
import csv
input_file = "inventory.csv"
output_file = "expensive.csv"
with open(input_file, newline="") as infile, \
open(output_file, "w", newline="") as outfile:
reader = csv.DictReader(infile)
writer = csv.DictWriter(outfile, fieldnames=reader.fieldnames)
writer.writeheader()
for row in reader:
if float(row["price"]) >= 1.0:
writer.writerow(row)
print(f"Filtered rows written to {output_file}.")Questo schema — aprire entrambi i file nello stesso blocco with, trasmettere le righe dal reader al writer — gestisce file di qualsiasi dimensione senza caricare tutto in memoria in una volta.
Capitoli Correlati
- Gestione dei File Python — apertura, lettura e scrittura di file di testo normale
- Lettura di File Python — lettura del contenuto di file con
read()ereadlines() - Scrittura e Creazione di File Python — scrittura e aggiunta di contenuto ai file
- Python JSON — utilizzo di JSON, un altro formato comune per lo scambio di dati
- Python Try Except — gestione delle eccezioni per file non trovati e altre situazioni