The csv module in the Python standard library reads and writes CSV (Comma-Separated Values) files, a widely used format for spreadsheets, data exports, and tabular data exchange. You can read rows as lists or as dictionaries keyed by column headers, and you can write data from lists or dictionaries with equal ease.
import csv
with open("students.csv", newline="") as file:
reader = csv.reader(file)
for row in reader:
print(row)The loop prints one list per row, starting with the header row itself, because csv.reader does not treat the first line as special in any way. Each value comes back as plain text, even the numeric-looking score column:
['name', 'score', 'grade']
['Maya', '92', 'A']
['Devin', '85', 'B']
['Priya', '78', 'C']csv.reader(file) returns an iterator over the rows. Each row is a list of strings. The first row typically contains column headers, but csv.reader treats it the same as any other row.
Always open CSV files with newline="". This prevents the csv module from adding extra carriage returns on Windows and is harmless on other platforms.
Reading CSV as dictionaries
Accessing values by numeric index gets confusing once a file has more than a few columns. csv.DictReader solves this by reading each row as a dict (an OrderedDict before Python 3.8) keyed by the header row, so you can look up a value by its column name instead.
import csv
with open("students.csv", newline="") as file:
reader = csv.DictReader(file)
for row in reader:
print(f"{row['name']} scored {row['score']}")Each row now behaves like a dictionary, so the loop reads values by column name instead of by position, which makes the code easier to follow when a CSV file has many columns:
Maya scored 92
Devin scored 85
Priya scored 78DictReader uses the first row as column names automatically. Each subsequent row becomes a dictionary where you access values by column name instead of numeric index.
If your CSV has no header row, pass the fieldnames yourself:
reader = csv.DictReader(file, fieldnames=["name", "score", "grade"])Writing CSV from lists
csv.writer writes rows from lists or tuples. Give it a file opened for writing, then pass either a single row to writerow or a full collection of rows to writerows, and the module takes care of adding commas and line endings correctly.
import csv
rows = [
["name", "score", "grade"],
["Maya", "92", "A"],
["Devin", "85", "B"],
]
with open("output.csv", "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(rows)writer.writerows(rows) writes all rows at once. For writing one row at a time, use writer.writerow(row).
Writing CSV from dictionaries
csv.DictWriter writes rows from dictionaries. You must provide the fieldnames so the writer knows which keys to include and in what order.
import csv
fieldnames = ["name", "score", "grade"]
rows = [
{"name": "Maya", "score": 92, "grade": "A"},
{"name": "Devin", "score": 85, "grade": "B"},
]
with open("grades.csv", "w", newline="") as file:
writer = csv.DictWriter(file, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(rows)writer.writeheader() writes the column names as the first row. writer.writerows(rows) writes the data rows. The fieldnames list determines both the header and the order of values in each output row.
Handling custom delimiters
Not all CSV files use commas. Tab-separated values (TSV) and semicolon-separated files are also common. Use the delimiter parameter.
import csv
with open("data.tsv", newline="") as file:
reader = csv.reader(file, delimiter="\t")
for row in reader:
print(row)The same delimiter argument works for semicolon-separated files, which are common in European CSV exports because some regional settings already use the comma as a decimal separator:
reader = csv.reader(file, delimiter=";")The delimiter parameter works the same way with DictReader, writer, and DictWriter.
Quoting and special characters
When a field contains the delimiter character, a newline, or a quote character, the csv module automatically wraps it in quotes. You can control this behavior with the quoting parameter.
import csv
data = [
["name", "description"],
["Maya", "Likes Python, hiking, and photography"],
["Devin", 'Says "hello" in 5 languages'],
]
with open("quoted.csv", "w", newline="") as file:
writer = csv.writer(file, quoting=csv.QUOTE_MINIMAL)
writer.writerows(data)QUOTE_MINIMAL (the default) only quotes fields that contain special characters. Other options:
| Quoting constant | Behavior |
|---|---|
| csv.QUOTE_MINIMAL | Quote only when necessary (default) |
| csv.QUOTE_ALL | Quote every field |
| csv.QUOTE_NONNUMERIC | Quote all non-numeric fields |
| csv.QUOTE_NONE | Never quote; raises error on special characters |
For most cases, the default QUOTE_MINIMAL is correct and produces clean output.
Reading from a string
Use io.StringIO to treat a string as a file-like object for the csv module.
import csv
from io import StringIO
data = "name,score,grade\nMaya,92,A\nDevin,85,B\n"
reader = csv.DictReader(StringIO(data))
for row in reader:
print(row)StringIO wraps the string so csv.DictReader can read it exactly as if it came from an open file, splitting on newlines and turning each data row into a dictionary keyed by the header:
{'name': 'Maya', 'score': '92', 'grade': 'A'}
{'name': 'Devin', 'score': '85', 'grade': 'B'}This is useful for testing CSV parsing logic or handling CSV data received from an API response. If the API instead returns nested or non-tabular data, reading and writing JSON files is usually a better fit than CSV.
Practical example: filtering and transforming CSV data
Combine reading and writing to transform a CSV file.
import csv
with open("employees.csv", newline="") as infile, \
open("engineers.csv", "w", newline="") as outfile:
reader = csv.DictReader(infile)
writer = csv.DictWriter(outfile, fieldnames=reader.fieldnames)
writer.writeheader()
for row in reader:
if row.get("department") == "Engineering":
writer.writerow(row)This script reads employees.csv, keeps only rows where the department is "Engineering", and writes the result to engineers.csv. Both files are opened together with the with statement, and both are properly closed when the block ends.
Common mistakes
Forgetting newline="". On Windows, opening a CSV file without newline="" inserts an extra blank line between every data row. This setting is required for correct CSV handling and is safe on all platforms.
Treating all values as strings. The csv module reads every field as a string. If you need numbers, convert them manually:
row["score"] = int(row["score"])Relying on column order with DictReader. DictReader returns dictionaries, so column order in the source file technically does not matter for access. But if your code assumes a specific order (like list(row.values())), a reordered input file will break it. Always access by column name.
Using csv.writer without a header. If you write data without a header row, readers cannot use DictReader later. Include a header row unless the file format explicitly omits it.
Rune AI
Key Insights
- Use
csv.reader(file)to read rows as lists andcsv.DictReader(file)to read rows as dictionaries keyed by header names. - Use
csv.writer(file)to write rows from lists andcsv.DictWriter(file, fieldnames=...)to write from dictionaries. - Always open CSV files with
newline=''to avoid extra blank lines on Windows. - Handle custom delimiters with the
delimiterparameter. - CSV files are read row by row, so they work efficiently with large files.
- Use the
quotingparameter to control how special characters and commas inside fields are handled.
Frequently Asked Questions
Should I use csv.reader or csv.DictReader?
How do I handle CSV files with a different delimiter?
Can the csv module handle large files?
Conclusion
The csv module is the standard tool for tabular data in Python. Use csv.reader for row-by-index access and csv.DictReader when you want to work with named columns. Always open CSV files with newline='' to prevent extra blank lines, and use the with statement to ensure files are properly closed.
More in this topic
Format Dates and Times in Python
Learn how to use strftime and strptime to format dates as strings and parse date strings into Python datetime objects.
What Is the Python Standard Library?
Learn what the Python standard library is, why it matters, and how to use its built-in modules without installing anything extra.
Encode and Decode Base64 Data in Python
Learn how to use Python's base64 module to encode binary data as text and decode Base64 strings back to bytes.