csv.DictReader and csv.DictWriter

· 5 min read · Updated March 14, 2026 · beginner
python stdlib csv files

When working with CSV files, using dictionaries instead of lists makes your code more readable and maintainable. Instead of remembering that column 0 is the name and column 1 is the age, you can use row["name"] and row["age"] which is self-documenting. Python’s csv module provides DictReader and DictWriter exactly for this purpose.

DictReader: Reading CSV into Dictionaries

csv.DictReader reads a CSV file and yields each row as a dictionary. The first row of your CSV file becomes the keys:

import csv

with open("users.csv", "r", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row)

Given a CSV file like this:

name,age,city
Alice,30,New York
Bob,25,San Francisco

The output would be:

{'name': 'Alice', 'age': '30', 'city': 'New York'}
{'name': 'Bob', 'age': '25', 'city': 'San Francisco'}

All values come as strings, so you’ll need to convert numbers explicitly:

with open("users.csv", "r", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(f"{row['name']} is {int(row['age'])} years old")

Custom Field Names

What if your CSV doesn’t have a header row, or you want different field names? Use the fieldnames parameter:

import csv

# CSV without headers
data = """Alice,30,New York
Bob,25,San Francisco"""

with open("users.csv", "w", newline="") as f:
    f.write(data)

# Read with custom fieldnames
with open("users.csv", "r", newline="") as f:
    reader = csv.DictReader(f, fieldnames=["name", "age", "city"])
    for row in reader:
        print(row)

Output:

{'name': 'Alice', 'age': '30', 'city': 'New York'}
{'name': 'Bob', 'age': '25', 'city': 'San Francisco'}

DictWriter: Writing CSV from Dictionaries

csv.DictWriter writes dictionaries to a CSV file. You must specify the field names:

import csv

data = [
    {"name": "Alice", "age": "30", "city": "New York"},
    {"name": "Bob", "age": "25", "city": "San Francisco"},
]

with open("output.csv", "w", newline="") as f:
    fieldnames = ["name", "age", "city"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    
    writer.writeheader()  # Writes the header row
    writer.writerows(data)

This creates:

name,age,city
Alice,30,New York
Bob,25,San Francisco

Writing a single row works with writerow():

with open("output.csv", "w", newline="") as f:
    fieldnames = ["name", "age", "city"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({"name": "Charlie", "age": "35", "city": "Chicago"})

Handling Missing Fields

When writing, you can specify what happens with missing values using the extrasaction parameter:

# Default: raises an error if dict has extra keys
writer = csv.DictWriter(f, fieldnames=["name", "age"])
# writer.writerow({"name": "Alice", "age": 30, "extra": "value"})  # Raises error!

# Ignore extra keys
writer = csv.DictWriter(f, fieldnames=["name", "age"], extrasaction="ignore")
writer.writerow({"name": "Alice", "age": 30, "extra": "value"})  # Works

You can also set default values:

data = [
    {"name": "Alice", "age": "30"},
    {"name": "Bob"},  # No age provided
]

with open("output.csv", "w", newline="") as f:
    fieldnames = ["name", "age"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    for row in data:
        # Add default for missing keys
        full_row = {"age": "unknown", **row}
        writer.writerow(full_row)

Using Different Delimiters

DictReader and DictWriter work with any delimiter, not just commas:

import csv

# Tab-separated values
with open("data.tsv", "r", newline="") as f:
    reader = csv.DictReader(f, delimiter="\t")
    for row in reader:
        print(row)

# Pipe-separated values  
data = [{"name": "Alice", "age": "30"}]
with open("data.psv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "age"], delimiter="|")
    writer.writeheader()
    writer.writerows(data)

Common delimiters:

  • , — Comma (standard CSV)
  • \t — Tab (TSV files)
  • ; — Semicolon (European CSV format)
  • | — Pipe (common in data processing)

Restricting Columns When Reading

Read only specific columns from a larger CSV:

import csv

# Only need name and email, not all columns
with open("users.csv", "r", newline="") as f:
    reader = csv.DictReader(f, fieldnames=["name", "email"])
    for row in reader:
        print(f"Name: {row['name']}, Email: {row['email']}")

This is useful when you have a wide CSV but only need a few fields.

Real-World Example: Processing Survey Data

A common use case is processing survey or form submission data:

import csv

# Sample survey responses
survey_data = """email,satisfaction,rating,comments
alice@example.com,good,4,Great service!
bob@example.com,excellent,5,Love it!
charlie@example.com,poor,2,Needs improvement"""

# Save sample data
with open("survey.csv", "w", newline="") as f:
    f.write(survey_data)

# Analyze the responses
ratings = []
with open("survey.csv", "r", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        ratings.append(int(row["rating"]))
        
average = sum(ratings) / len(ratings)
print(f"Average rating: {average:.1f}")
# Output: Average rating: 3.7

# Find low-rated responses
with open("survey.csv", "r", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        if int(row["rating"]) <= 2:
            print(f"Low rating from {row['email']}: {row['comments']}")
# Output: Low rating from charlie@example.com: Needs improvement

Common Pitfalls

Forgetting newline=""

# Wrong - causes double newlines on Windows
with open("file.csv", "w") as f:
    writer = csv.DictWriter(f, fieldnames=["a", "b"])
    writer.writeheader()

# Correct
with open("file.csv", "w", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["a", "b"])
    writer.writeheader()

Mismatched fieldnames

# Dict has different keys than fieldnames
fieldnames = ["name", "age"]
data = [{"username": "Alice", "years": 30}]  # Wrong keys!

# Fix by matching keys
data = [{"name": "Alice", "age": 30}]  # Correct keys

Not converting types

# Values are always strings
row = {"age": "30"}  # Still a string!
age = int(row["age"])  # Convert explicitly

When to Use DictReader/DictWriter

Choose dictionary-based CSV handling when:

  • You want self-documenting code with named fields
  • Your CSV has many columns and positional access is error-prone
  • You’re transforming data between different formats
  • You need to filter or select specific columns

For simple one-off reads with few columns, csv.reader is fine. But as your data grows or your code needs to be maintainable, DictReader and DictWriter pay off quickly.

See Also