CSV files with csv module
Learn to read and write CSV files using Python's csv module. This step-by-step tutorial covers opening CSV files, using DictReader and DictWriter, handling headers, and common edge cases like missing values and delimiters.
Focus: work with csv files using the csv module
You've written scripts that process data lists, maybe even used list comprehensions to filter records. But real data rarely comes as Python lists — it comes as CSV files exported from spreadsheets, databases, or APIs. In this lesson, you'll learn to work with CSV files using the csv module in Python, turning raw rows into structured data without reinventing parsing logic.
The problem this lesson solves
Without the csv module, handling comma-separated values is error-prone. Splitting a line like name, city with .split(',') breaks when a field contains a comma inside quotes — think "Doe, John",NYC. Python's csv module handles these edge cases: quoted fields, different delimiters, newlines inside cells, and header rows. It's the Pythonic, robust way to work with tabular data in files.
Core concept / mental model
Think of a CSV file as a spreadsheet saved as plain text: the first row is often column headers, and every subsequent row is a record. The csv module acts as a translator between this row-based text and Python data structures.
Mental model: Imagine a CSV file as a train. The header is the locomotive — it tells you what each car (column) contains. Each row after is a passenger car with values matching that header. The
csv.readergives you each row as a list;csv.DictReadergives you each row as a dictionary using the header as keys.
How it works step by step
1. Import and open the file
Always use with open(...) to ensure the file closes properly. Pass the file object to the csv reader or writer.
2. Choose your reader
csv.reader: Returns each row as a list of strings.csv.DictReader: Returns each row as anOrderedDictusing the first row's headers as keys.
3. Process rows
Loop over the reader object. For a reader, access fields by index (e.g., row[0]). For a DictReader, access by header name (e.g., row['name']).
4. Write files
Use csv.writer or csv.DictWriter. For DictWriter, you must specify fieldnames and call writeheader().
Hands-on walkthrough
Reading with csv.reader
import csv
with open('users.csv', 'w') as f:
# Create sample file first
f.write('Alice,30,alice@example.com\n')
f.write('Bob,25,bob@example.com')
with open('users.csv', 'r') as f:
reader = csv.reader(f)
for row in reader:
print(row) # Each row is a list
Output:
['Alice', '30', 'alice@example.com']
['Bob', '25', 'bob@example.com']
Reading with DictReader (handles headers automatically)
with open('users.csv', 'w') as f:
f.write('name,age,email\n') # header row
f.write('Alice,30,alice@example.com\n')
f.write('Bob,25,bob@example.com')
with open('users.csv', 'r') as f:
reader = csv.DictReader(f)
for row in reader:
print(f"{row['name']} is {row['age']} years old, email: {row['email']}")
Output:
Alice is 30 years old, email: alice@example.com
Bob is 25 years old, email: bob@example.com
Writing with csv.writer
with open('output.csv', 'w', newline='') as f:
writer = csv.writer(f)
writer.writerow(['name', 'age', 'city']) # header
writer.writerow(['Alice', 30, 'New York'])
writer.writerow(['Bob', 25, 'San Francisco'])
Result (output.csv):
name,age,city
Alice,30,New York
Bob,25,San Francisco
Pro tip: Always use
newline=''when opening a file for writing withcsv.writer. Otherwise, on Windows, extra blank lines appear between rows.
Writing with DictWriter
import csv
with open('employees.csv', 'w', newline='') as f:
fieldnames = ['name', 'department', 'salary']
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({'name': 'Alice', 'department': 'Engineering', 'salary': 100000})
writer.writerow({'name': 'Bob', 'department': 'Marketing', 'salary': 85000})
Output (employees.csv):
name,department,salary
Alice,Engineering,100000
Bob,Marketing,85000
Compare options / when to choose what
| Feature | csv.reader / csv.writer | csv.DictReader / csv.DictWriter |
|---|---|---|
| Row representation | List of strings | Dict (keyed by header) |
| Header handling | Not automatic; you skip first row manually | Automatically uses first row as keys |
| Ease of field access | Index-based: row[0] |
Name-based: row['name'] |
| When to use | Simple, fixed-column data; performance-critical | Data with named columns; headers present |
| Writing complexity | Just pass values as lists | Need fieldnames list and dict per row |
Choose DictReader when: You know the column names, want readable code, or the file has headers. Choose reader when: You need maximum speed, have no headers, or columns are positional.
Troubleshooting & edge cases
Missing values in rows
If a row has fewer fields than the header expects, DictReader returns None for missing keys. Use row.get('field', '') or check with row['field'] is not None.
Different delimiters (e.g., tab-separated)
Specify the delimiter parameter:
reader = csv.reader(f, delimiter='\t') # TSV files
Quoted fields with commas inside
CSV module handles quotes automatically. If your data uses single quotes, set quoting=csv.QUOTE_NONNUMERIC or escapechar.
Encoding issues (especially Excel files)
Assume UTF-8. If you get UnicodeDecodeError or see garbled characters, specify encoding='utf-8-sig' (for BOM) or try encoding='latin-1'.
File not found / wrong path
Use os.path.exists() to check. Use relative paths from your script's location, or absolute paths.
What you learned & what's next
You now understand how to:
- Open and read CSV files using both csv.reader and csv.DictReader
- Write CSV files with csv.writer and csv.DictWriter
- Handle headers, different delimiters, and common encoding pitfalls
This skill is essential before moving to JSON file handling (next lesson), where you'll work with structured data that's nested, not tabular. You'll also use CSV reading when you learn pandas later in the track.
Next step: In the next lesson, you'll learn to parse and generate JSON files using Python's
jsonmodule — perfect for API responses and configuration files.
Practice recap
Create a file inventory.csv with columns: product,quantity,price. Write a script that reads it using DictReader, calculates total value per product (quantity × price), and writes a new CSV with columns product,total_value. Bonus: handle rows where quantity or price might be missing (assume 0). Test with a CSV containing quoted fields with commas.
Common mistakes
- Forgetting
newline=''when opening a file for writing withcsv.writer— causes extra blank lines on Windows. - Using
.split(',')instead ofcsv.reader— breaks on fields containing commas inside quotes. - Assuming all CSV files use commas — forgetting to set
delimiter='\t'for TSV files leads to one-element rows. - Not handling missing values in DictReader — accessing
row['missing_field']raises KeyError.
Variations
- Use
csv.DictReaderwithfieldnamesparameter if your CSV has no header row but you want dict output:DictReader(f, fieldnames=['col1', 'col2']). - Specify
quoting=csv.QUOTE_ALLto force quoting of all fields when writing, ensuring compatibility with strict parsers. - Use
csv.Snifferto automatically detect delimiter, quote character, and header presence from a sample of the file.
Real-world use cases
- Migrating user data from an old CRM: export CSV, read with DictReader, transform fields, write new CSV for import.
- Processing daily sales reports: read CSV with reader, aggregate totals per region, export summary as CSV for management.
- Loading configuration from a CSV file: use DictReader to map parameters to Python dictionaries for flexible application setup.
Key takeaways
- Use
csv.readerfor simple, positional data;csv.DictReaderwhen headers exist and field names are known. - Always open CSV files with
with open(..., newline='')for cross-platform safety (writing) andwith open(...)for reading. - Specify
encoding='utf-8-sig'for Excel-generated CSVs with BOM; usedelimiter='\t'for tab-separated files. - Handle missing values with
row.get('field', default)when using DictReader. - Writing with
DictWriterrequires settingfieldnamesand callingwriteheader()before writing rows. - The csv module is a battle-tested standard library component — prefer it over manual splitting for any real-world CSV work.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.