DictReader and DictWriter

csv · Essentials · 9 min

Accessing row['email'] instead of row[3] keeps code correct when columns are added or reordered.

`csv.DictReader(f)` uses the first row as field names and yields each following row as a dict: row["email"]. Since Python 3.8 these are plain dicts, in column order.

  • reader.fieldnames gives the header.
  • Pass fieldnames=[...] if the file has no header row; then the first row is treated as data.
  • If a row has more fields than the header, extras go into a list under the restkey (default None); missing fields get restval (default None).

`csv.DictWriter(f, fieldnames=[...])` writes dicts:

  • writer.writeheader() writes the field names row; call it once.
  • writer.writerow(d) / writerows(dicts): keys are matched to columns; missing keys get restval (default empty).
  • A dict with a key not in fieldnames raises ValueError, unless you pass extrasaction="ignore".

fieldnames also controls column order in the output, so you can reorder or select columns when transforming files. A typical pipeline reads with DictReader, transforms each dict, and writes with DictWriter, streaming row by row.

Example

import csv

with open("users.csv", "w", newline="", encoding="utf-8") as f:
    w = csv.DictWriter(f, fieldnames=["id", "email", "plan"])
    w.writeheader()
    w.writerow({"id": 1, "email": "ada@x.io", "plan": "pro"})
    w.writerow({"id": 2, "email": "bob@x.io"})              # plan -> ''

with open("users.csv", newline="", encoding="utf-8") as f, \
     open("emails.csv", "w", newline="", encoding="utf-8") as out:
    reader = csv.DictReader(f)
    print(reader.fieldnames)                  # ['id', 'email', 'plan']
    writer = csv.DictWriter(out, fieldnames=["email", "id"], extrasaction="ignore")
    writer.writeheader()
    for row in reader:
        print(row)                            # {'id': '1', 'email': 'ada@x.io', 'plan': 'pro'} ...
        writer.writerow(row)                  # 'plan' ignored, columns reordered

print(open("emails.csv").read().split())      # ['email,id', 'ada@x.io,1', 'bob@x.io,2']

Remember

  • DictReader yields one dict per row, keyed by the header
  • DictWriter needs fieldnames and writeheader()
  • extrasaction='ignore' drops keys that aren't columns

Watch out for

  • Forgetting writeheader(), producing a file without column names.

Check yourself

  1. DictWriter(f, fieldnames=['a']).writerow({'a': 1, 'b': 2}) is called. What happens?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/csv.html#csv.DictReader