Skip to content
beginner

Handling CSV Files in Python: Reading and Writing

CSV files are how the working world hands data to Python. If you've ever exported a spreadsheet, downloaded a report from a website, or pulled data from a…

Published 2026-09-05Updated 2026-09-128 min read
Stunning aerial view of Sacramento's city skyline illuminated at night, showcasing bustling urban life.
Stunning aerial view of Sacramento's city skyline illuminated at night, showcasing bustling urban life. Photo by Stephen Leonardi on Pexels.

CSV files are how the working world hands data to Python. If you've ever exported a spreadsheet, downloaded a report from a website, or pulled data from a database, you've probably ended up with a .csv file. Learning to read and write these files with Python's built-in csv module means you can stop copying data by hand and start processing it with code.

What a CSV file actually is

CSV stands for comma-separated values. It's a plain-text format for storing tabular data—think of it as a spreadsheet stripped down to its bare bones. Each line is a row, and commas separate the columns.

Here's what a small CSV file named employees.csv might look like:

Name,Department,Salary
Alice,Engineering,85000
Bob,Marketing,62000
Carol,Sales,74000

The first row is the header row, which names each column. The rows below hold the actual data.

You could try to read this file by hand with something like line.split(","), and for this simple example, it would work. But CSV has a few sneaky edge cases. What if a value contains a comma, like "Doe, John"? What if a field is wrapped in quotes? What if a value contains a newline?

That's why Python ships with a dedicated csv module. It handles all those edge cases so you don't have to reinvent a parser that the Python core team has already debugged for you.

Setting up your first CSV example

Before you run any code, make sure your files are in the right place. Python looks for files in the same folder as your script by default.

Create a folder for this tutorial and save two files in it:

  • employees.csv with the content shown above
  • read_employees.py with the code below

If you run your script and Python raises FileNotFoundError, the most likely cause is that employees.csv isn't in the same folder as your script. Check the folder, confirm the filename is spelled exactly the same way, and try again.

Reading a CSV file with csv.reader

Let's start with the simplest way to read a CSV file. The csv.reader function turns each row into a list of strings.

Create a file called read_employees.py with this code:

import csv

with open("employees.csv", newline="", encoding="utf-8") as file:
    reader = csv.reader(file)
    for row in reader:
        print(row)

Then run it:

python read_employees.py

Expected output:

['Name', 'Department', 'Salary']
['Alice', 'Engineering', '85000']
['Bob', 'Marketing', '62000']
['Carol', 'Sales', '74000']

Notice two things right away.

First, the newline="" argument in open(). This is a Python quirk: the csv module handles line endings itself, and if you don't pass newline="", you can end up with blank lines between rows when writing files. Get in the habit of always including it when working with CSV files.

Second, every value comes back as a string. 85000 looks like a number, but Python sees the text "85000". If you want to do math with it, you'll need to convert it with int() or float().

The encoding="utf-8" argument tells Python how to decode the text in the file. UTF-8 is the standard encoding for most modern files, so including it gives you a consistent template that handles names, symbols, and other characters correctly.

Knowledge check

Check your understanding

Answer this question before you continue.

After reading the employees file with csv.reader, what type is the value returned for the Salary field in the row for Alice?
Misconception Check

Focus: Recognize that csv.reader returns CSV fields as strings and convert numeric text before doing arithmetic or numeric comparisons.

Reading with column names using csv.DictReader

The csv.reader approach works, but it has a readability problem. When you get a row back as a list, you have to remember that row[1] is the department and row[2] is the salary. That gets old fast.

The csv.DictReader class solves this by using the header row as dictionary keys. Each row becomes a dictionary where you access values by column name.

import csv

with open("employees.csv", newline="", encoding="utf-8") as file:
    reader = csv.DictReader(file)
    for row in reader:
        print(row)

Expected output:

{'Name': 'Alice', 'Department': 'Engineering', 'Salary': '85000'}
{'Name': 'Bob', 'Department': 'Marketing', 'Salary': '62000'}
{'Name': 'Carol', 'Department': 'Sales', 'Salary': '74000'}

Now you can access a single field by name:

import csv

with open("employees.csv", newline="", encoding="utf-8") as file:
    reader = csv.DictReader(file)
    for row in reader:
        print(f"{row['Name']} works in {row['Department']}")

Expected output:

Alice works in Engineering
Bob works in Marketing
Carol works in Sales

So which should you use? My rule is simple: use csv.reader when you just need to process rows quickly and don't care about column names. Use csv.DictReader when your file has a header row and you want to refer to columns by name—which is most of the time, honestly. Named access is easier to read, easier to debug, and less likely to break if someone reorders the columns in the source file.

Here's a concrete example of why that matters. Imagine someone swaps the columns in employees.csv so Department comes first:

Department,Name,Salary
Engineering,Alice,85000

With csv.reader, your code that expected row[0] to be the name now silently prints the department instead. With csv.DictReader, row['Name'] still finds the right value no matter where the column sits. That resilience is worth the extra keystrokes.

Knowledge check

Check your understanding

Answer this question before you continue.

Which expression accesses Alice's department by column name when iterating over rows from csv.DictReader?
Single Choice

Focus: Choose csv.DictReader when a CSV header should provide readable column-name access.

The CSV header is Name,Department,Salary.

Writing a CSV file with csv.writer

Reading is only half the story. Sooner or later, you'll want to save data from your Python program so someone else can open it in a spreadsheet.

The csv.writer function writes rows from lists. Here's how to create a new CSV file:

import csv

with open("new_employees.csv", "w", newline="", encoding="utf-8") as file:
    writer = csv.writer(file)
    writer.writerow(["Name", "Department", "Salary"])
    writer.writerow(["David", "Engineering", 91000])
    writer.writerow(["Eve", "Design", 68000])

Run this script, then open new_employees.csv in any text editor or spreadsheet program. You'll see:

Name,Department,Salary
David,Engineering,91000
Eve,Design,68000

A few things to notice:

  • writerow() writes a single row. Pass it a list, and each element becomes one field.
  • writerows() (with an s) writes multiple rows at once. Pass it a list of lists.
  • Numbers are converted to strings automatically. You don't need to call str() yourself.

Writing with column names using csv.DictWriter

Just as DictReader pairs naturally with reading, csv.DictWriter pairs with writing when your data lives in dictionaries.

DictWriter needs one extra piece of information: fieldnames. This is an ordered list that tells Python which dictionary keys map to which columns, and in what order.

import csv

with open("filtered_employees.csv", "w", newline="", encoding="utf-8") as file:
    fieldnames = ["Name", "Department", "Salary"]
    writer = csv.DictWriter(file, fieldnames=fieldnames)

    writer.writeheader()

    writer.writerow({"Name": "Alice", "Department": "Engineering", "Salary": 85000})
    writer.writerow({"Name": "Carol", "Department": "Sales", "Salary": 74000})

Expected file contents:

Name,Department,Salary
Alice,Engineering,85000
Carol,Sales,74000

The writeheader() method writes the fieldnames as the header row. Then each writerow() call takes a dictionary and writes the values in the order specified by fieldnames.

This pattern is how you save filtered or cleaned data back to a file. Read data in with DictReader, process it, then write it out with DictWriter—the column names stay intact the whole way through.

Knowledge check

Check your understanding

Answer this question before you continue.

In the DictWriter example, what does writer.writeheader() do?
Single Choice

Focus: Use DictWriter fieldnames and writeheader() to write named CSV columns in a chosen order.

fieldnames = ["Name", "Department", "Salary"]

Common beginner mistakes

Every Python developer hits these when they start working with CSV files. Here's what to watch for.

Forgetting newline=""

Symptom: Your output file has blank lines between every row.

Fix: Always open CSV files with newline="":

with open("output.csv", "w", newline="") as file:

Assuming csv.reader returns numbers

Symptom: You try to compare a salary field with if row[2] > 70000 and get a TypeError, or your comparisons behave strangely because you're comparing strings, not numbers.

Fix: Remember that every value from csv.reader and DictReader is a string. Convert explicitly when you need numbers:

salary = int(row["Salary"])

Splitting lines manually

Symptom: Your data gets corrupted when a field contains a comma, like "Doe, John".

Fix: Don't use line.split(","). That's exactly the problem the csv module was built to solve. Use csv.reader and let Python handle the quoting rules.

Knowledge check

Check your understanding

Answer this question before you continue.

A CSV field such as "Doe, John" is being split into two fields by this code. Which fix follows the article's recommendation?
Debugging

Focus: Replace manual comma splitting with csv.reader so quoted fields containing commas are parsed correctly.

with open("people.csv", encoding="utf-8") as file:
    for line in file:
        fields = line.split(",")

Forgetting to import csv

Symptom: NameError: name 'csv' is not defined.

Fix: Add import csv at the top of your script. It's a built-in module, so no installation needed—just the import.

Practice: read, filter, and write

Flowchart showing sales.csv entering DictReader, rows being filtered where Price is greater than 200, and matching Product, Category, and Price rows being written through DictWriter to expensive_products.csv.
This workflow connects the tutorial’s main skills: read structured rows, apply a numeric filter, and preserve column names while writing the results.

Here's a small drill to tie everything together. Create a file called sales.csv with this data:

Product,Category,Price
Laptop,Electronics,1200
Desk Chair,Furniture,250
Coffee Maker,Appliances,80
Monitor,Electronics,300
Bookshelf,Furniture,150

Your task: read this file, keep only the rows where the price is greater than 200, and write the result to a new file called expensive_products.csv.

Before you look at the solution, try writing the filter condition yourself. Which products should appear in the final file? Write down your prediction, then check it against the output.

A good starter approach uses DictReader and DictWriter so the column names stay intact:

import csv

with open("sales.csv", newline="", encoding="utf-8") as infile:
    reader = csv.DictReader(infile)
    rows = [row for row in reader if int(row["Price"]) > 200]

with open("expensive_products.csv", "w", newline="", encoding="utf-8") as outfile:
    fieldnames = ["Product", "Category", "Price"]
    writer = csv.DictWriter(outfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(rows)

When you're done, open expensive_products.csv and check that it contains only Laptop, Desk Chair, and Monitor. If it does, you've just completed the full workflow: read, filter, write.

What's next

You now know how to move data between CSV files and Python. The natural next step is to combine this skill with lists, dictionaries, and file handling in a small real project. That's exactly what you'll do in a simple data project, where reading and writing CSV files become part of a complete data workflow.

One decision rule to carry forward: use reader and writer for simple row-by-row work, and reach for DictReader and DictWriter whenever column names matter. That single choice will keep your code readable and your data intact.

Knowledge check

Final check

Finish the article by checking the ideas you just learned.

Using the practice code with the condition int(row["Price"]) > 200, which products appear in expensive_products.csv?
Question 1 of 2Output Prediction

Focus: Apply DictReader filtering with an integer price comparison to identify which rows should be written.

The source prices are Laptop 1200, Desk Chair 250, Coffee Maker 80, Monitor 300, and Bookshelf 150.
You have a list representing one CSV row: ["Eve", "Design", 68000]. Which call writes that single row with csv.writer?
Question 2 of 2Single Choice

Focus: Select csv.writer and the appropriate row-writing method for writing list-based CSV data.

writer = csv.writer(file)

References

  1. csv — CSV File Reading and Writing — Python 3.15.0a8 documentationdocs.python.org
8sources checked
8source domains
5searches run

Research updated Sep 5, 2026

Practical resource

Want a more structured Python path?

Use the Python Starter Pack to turn scattered tutorials into a focused practice path.

View the bundle
Coming soon

Python Starter Pack

A compact LearnPyFast PDF pack covering what Python is, installation, your first program, running Python code, and Python versions.

$9
PDF BundleTopic PackPythonBeginner
  • 5 curated chapters
  • Enhanced PDF edition with bundle-only learning guidance
  • Offline-friendly format for focused review
  • Source article links for future online updates

Coming soon

Free Python bundle

Get the LearnPyFast Python Starter Bundle

A focused collection of beginner-friendly Python resources to help you move from setup to building practical projects.

You’ll receive the bundle by email. You can unsubscribe anytime.

No spam. You can unsubscribe anytime. See our Privacy policy.

Related sites

Continue beyond Python

Explore related Worldmonger sites when you want to move from Python basics into JavaScript or LLM application building.

JavaScript tutorialstutorial

LearnJSFast

Beginner-friendly JavaScript tutorials for practical web development and self-taught developers.

JavaScriptFrontendWeb development
Visit LearnJSFast
LLM tutorialstutorial

LearnLLMFast

Practical LLM tutorials for builders who want to understand prompting, workflows, agents, and AI applications.

LLMAIBuilders
Visit LearnLLMFast

Keep learning

Related tutorials

Continue with nearby Python topics and beginner-friendly explanations.

Vibrant autumn landscape featuring a solitary oak tree in a green field under a cloudy sky.
beginner
10 min read

Basic File I/O in Python

A Python program that never touches a file forgets everything the moment it exits. File I/O is how your code keeps data after the run ends—saving notes,…

Read tutorial
Teacher conducting a lesson with engaged students in a modern classroom setting.
beginner
11 min read

How to Count Words in Python

Counting words in Python sounds trivial until you try it on real text. The moment your sentence contains a comma, a capital letter, or an ellipsis, the…

Read tutorial