Reading and writing CSV
Parse tabular files reliably with Python's built-in csv module.
- Open CSV files correctly with newline='' and read rows with csv.reader
- Use csv.DictReader to get rows as dictionaries keyed by header
- Write rows and headers with csv.writer and csv.DictWriter
- Handle custom delimiters and quoting options
- Explain why every CSV value arrives as a string and convert appropriately
CSV (comma-separated values) is the lingua franca of tabular data. Python's
standard-library csv module handles the tricky edge cases — quoted fields,
embedded commas, varying line endings — so you rarely need to split strings
manually.
Opening a file correctly
The module spec says to open files with newline='' and let the csv reader
handle line endings itself. Skip that argument and you'll see blank rows on
Windows:
import csv
with open("data.csv", newline="") as f:
reader = csv.reader(f)
for row in reader:
print(row) # each row is a list of stringsThe context manager from the previous lesson does the right thing here: the file is guaranteed closed even if an exception occurs mid-iteration.
Reading into dictionaries with DictReader
When the file has a header row, csv.DictReader maps each row to an
OrderedDict (or plain dict in Python 3.8+) keyed by the column names. This
is almost always what you want for real files:
with open("people.csv", newline="") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["age"])No magic column indexes, no off-by-one errors when someone inserts a column.
Every value from csv.reader and csv.DictReader is a string, even if it
looks like a number. After reading, convert explicitly: int(row["age"]),
float(row["price"]). Forgetting this is the most common CSV bug.
Writing with csv.writer
csv.writer handles quoting automatically — if a field contains a comma or a
quote character it wraps it properly so the output is valid CSV:
import csv
rows = [["Alice", 30], ["Bob, Jr.", 25]] # notice the comma in the second name
with open("out.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["name", "age"]) # header first
writer.writerows(rows) # all data rows at onceWriting dictionaries with DictWriter
When your data is already a list of dicts, DictWriter writes a header row and
maps keys to columns for you:
import csv
people = [{"name": "Alice", "age": 30}, {"name": "Bob", "age": 25}]
with open("out.csv", "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["name", "age"])
writer.writeheader()
writer.writerows(people)Pass fieldnames in the order you want the columns to appear.
Custom delimiters and quoting
Not every "CSV" is comma-separated. Pass delimiter to handle TSV files or
semicolon-separated exports:
csv.reader(f, delimiter="\t") # tab-separated
csv.reader(f, delimiter=";") # semicolons, common in European localesThe quoting parameter controls how the writer wraps values —
csv.QUOTE_NONNUMERIC quotes all non-numeric fields, which is a defensive choice
when downstream parsers are strict.
Where to go next
Next up: Working with JSON — serialising and parsing the structured data format that drives most web APIs.