csv.DictReader and csv.DictWriter
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
- csv-module — Complete reference for the csv module
- csv-processing — General CSV processing guide with pandas
- reading-json — Working with JSON files in Python