Code of the Day
IntermediateData I/O & manipulation

Reading and writing CSV

Parse tabular files reliably with Python's built-in csv module.

PythonIntermediate9 min read
Recommended first
By the end of this lesson you will be able to:
  • 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

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 strings

The 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 once

Writing 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 locales

The 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.

Python — editable, runs in your browser

Where to go next

Next up: Working with JSON — serialising and parsing the structured data format that drives most web APIs.

Finished reading? Mark it complete to track your progress.

On this page