Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

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

Sponsored

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.reader gives you each row as a list; csv.DictReader gives 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 an OrderedDict using 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 with csv.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 json module — 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 with csv.writer — causes extra blank lines on Windows.
  • Using .split(',') instead of csv.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

  1. Use csv.DictReader with fieldnames parameter if your CSV has no header row but you want dict output: DictReader(f, fieldnames=['col1', 'col2']).
  2. Specify quoting=csv.QUOTE_ALL to force quoting of all fields when writing, ensuring compatibility with strict parsers.
  3. Use csv.Sniffer to 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.reader for simple, positional data; csv.DictReader when headers exist and field names are known.
  • Always open CSV files with with open(..., newline='') for cross-platform safety (writing) and with open(...) for reading.
  • Specify encoding='utf-8-sig' for Excel-generated CSVs with BOM; use delimiter='\t' for tab-separated files.
  • Handle missing values with row.get('field', default) when using DictReader.
  • Writing with DictWriter requires setting fieldnames and calling writeheader() before writing rows.
  • The csv module is a battle-tested standard library component — prefer it over manual splitting for any real-world CSV work.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.