How to read a CSV file in Python

Use the built-in CSV module when you need rows without another dependency. Use pandas when you need column math, filtering, or grouping. The examples keep the answer copyable, then deal with headers, writing, encodings, and the Excel quirks that cause real failures.

🎙️ Published & recorded: ·

No dependencies: csv.DictReader

DictReader uses the first row as column names, so each later row is a dictionary. Open the file with newline set to an empty string because the CSV module needs to control newlines itself. State UTF-8 rather than trusting the operating system default. Every value still arrives as text, so convert amounts before doing arithmetic.

import csv

with open("users.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        print(row["name"], row["email"])
        total += float(row["amount"])

# row = {"name": "Ada", "email": "[email protected]", ...}

Prefer named fields over row zero and row two. The code survives a reordered file, and a missing header produces a useful KeyError instead of silently reading the wrong column.

Headers, plain rows, and pandas

Plain csv reader returns lists. Call next once only when the file really has a header you want to skip. For analysis, pandas reads a whole table and infers column types. Set the separator explicitly for semicolon exports, and use selected columns when a wide file wastes memory.

with open("data.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)
    next(reader)                    # skip header, if present
    for row in reader:
        print(row[0], row[2])
import pandas as pd

df = pd.read_csv("users.csv")
df.head()                          # first 5 rows
df["amount"].sum()                # typed column math

pd.read_csv("f.csv", sep=";")
pd.read_csv("f.csv", skiprows=2)
pd.read_csv("f.csv", usecols=["name", "amount"])

Choose plainly: if rows feed your program, the standard library is enough. If you are grouping, joining, filtering, or calculating across columns, pandas earns its installation cost.

Write a CSV back out

DictWriter needs the output column order up front. Write the header once, then write the dictionaries. Keep newline empty on Windows too; leaving it out is the usual cause of a blank line appearing between every record.

rows = [{"name": "Ada", "score": 95}, {"name": "Lin", "score": 88}]

with open("out.csv", "w", newline="", encoding="utf-8") as f:
    w = csv.DictWriter(f, fieldnames=["name", "score"])
    w.writeheader()
    w.writerows(rows)

Do not build rows by joining values with commas. A name such as Smith, John needs quoting and escaping, and the writer handles that correctly.

Fix encoding, BOM, and parsing failures

A common Windows failure is UnicodeDecodeError: charm ap codec can't decode byte zero x nine d. It means Python used the Windows default encoding for a file that is probably UTF-8. Add encoding equals UTF-8 to open. If an Excel export leaves an invisible marker before the first heading, use UTF-8 sig instead.

UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d
# fix:
open("users.csv", newline="", encoding="utf-8")

KeyError: 'name'
# if print(reader.fieldnames) shows '\ufeffname', remove the Excel BOM:
open("users.csv", newline="", encoding="utf-8-sig")
Debug in this order
Print reader.fieldnames first. If the first name starts with \ufeff, switch to utf-8-sig. If every row appears as one giant field, inspect the file and set delimiter=";" or pandas sep=";". If output has blank lines on Windows, add newline="".

Never repair a real CSV with line split comma. The value Smith, John is legal when quoted, and manual splitting silently turns it into two columns. Use the parser and fix its encoding or delimiter rather than replacing it.

📚 This is one page of our Python series. The full crash course (with audio for your commute): Python in 10 Minutes →

Tell me what missed

A correction is more useful than a compliment. This goes straight to the person who writes SwiftGrasp.

Was this page useful?
0/1000

Please do not include passwords, private keys, or personal information.