Python Tutorial / Read and Write CSV Files
CSV stores rows and fields as text. Use the csv module to handle delimiters and quoting, then validate and convert numeric fields because DictReader normally returns their values as strings.
Parse CSV rather than splitting on commas
A quoted field can contain commas or newlines. split(",") does not interpret those rules. DictReader maps fields using the header row, but your input policy must still address duplicate names and inconsistent field counts.
Open CSV files with newline="" so the csv module handles newlines. Reading UTF-8 with utf-8-sig accepts a byte-order mark, which otherwise can appear at the beginning of the first header field in files exported by some tools.
For the relevant APIs and platform requirements, see Python: csv.
Write a quoted name and calculate a total
The example replaces expenses-demo.csv in a disposable practice folder. Save and execute the entire program:
Save the complete code below as csv_demo.py in a separate practice folder, using UTF-8. Run python csv_demo.py in a terminal with your project virtual environment selected. Outside a virtual environment on macOS or Ubuntu, use python3 when that is your interpreter command.
import csv
from pathlib import Path
path = Path("expenses-demo.csv")
with path.open("w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["name", "amount"])
writer.writeheader()
writer.writerows([{ "name": "lunch, team", "amount": 8000}, {"name": "bus", "amount": 2500}])
total = 0
with path.open(encoding="utf-8-sig", newline="") as f:
reader = csv.DictReader(f)
if reader.fieldnames != ["name", "amount"]:
raise ValueError("unexpected header")
for row in reader:
total += int(row["amount"])
print(row["name"])
print("total:", total)
Expected output:
lunch, team bus total: 10500
Define numeric and row-validation rules
Blank amounts, thousands separators and currency suffixes cannot all be passed directly to int(). Define accepted formats and error reporting before stripping characters. Unrestricted cleanup can make invalid input appear legitimate.
enumerate(reader, start=2) can label logical records after the header. If quoted fields contain newlines, that number differs from a physical line number in the source file. State which kind of position an error report identifies.
A quoted field such as "coffee, large" is one CSV field. csv.reader restores one string, while a plain split produces two pieces. Inspect the saved text for quoting, then read it back with csv.reader and compare both field counts and values. A visible comma does not by itself indicate an extra column.
Check reruns and spreadsheet exports
CSV does not enforce field types or spreadsheet formula policies. A spreadsheet may interpret externally supplied values beginning with = as formulas. Shared exports need validation and text handling appropriate to the receiving application; quoting a field alone does not settle formula interpretation.
- Verify that lunch, team remains one name field and the record has two columns.
- Change the amount header to cost and confirm that validation stops the program.
- Restore the header and rerun: w mode should replace the example rather than keep adding rows.
For a complete import with rejected-record reporting, see the CSV validation project.




