SnippetPython

Read a CSV as dictionaries

Reads a CSV file into a list of dictionaries keyed by header row, with the encoding and newline handling that avoids the usual gotchas.

Last updated

Snippetpython
import csv

def read_csv_dicts(path):
    with open(path, newline="", encoding="utf-8") as f:
        return list(csv.DictReader(f))

# rows = read_csv_dicts("users.csv")
# rows[0]["email"]

How it works

csv.DictReader turns the first row into field names and every row after it into a dict keyed by those names, so callers read rows[i]["email"] by column name instead of tracking a fragile positional index that breaks the moment a column gets reordered.

The two open() arguments are both there for a specific bug each: newline="" hands the file to the csv module exactly as Python's own docs recommend, so it (not the platform's universal-newlines layer) is the one deciding how embedded newlines inside quoted fields are handled; encoding="utf-8" is stated explicitly rather than left to the platform default, which is ASCII-ish on some Windows locales and would otherwise raise on the first non-ASCII name or accented character.

Edge cases to know

  • list(...) reads the whole file into memory at once — fine for typical CSVs, but for a multi-gigabyte file, iterate the DictReader directly (for row in csv.DictReader(f): ...) instead of collecting it into a list.
  • A CSV saved with a different encoding (e.g. Windows-1252 from older Excel exports) will raise a UnicodeDecodeError with encoding="utf-8" — pass the actual source encoding, or encoding="utf-8-sig" if the file has a BOM.
  • Rows with more or fewer fields than the header get padded with None or collected into a list under the None key rather than raising — check for that key if the source data isn't guaranteed clean.

Related in Snippets