Working with CSV & JSON
Read and write CSV with DictReader/DictWriter, JSON load/dump, invalid input, custom types and JSON Lines.
Two text formats dominate everyday data exchange. CSV (comma-separated values) is how spreadsheets, bank statements and database exports travel. JSON (JavaScript Object Notation) is the language of web APIs and configuration files. Python's standard library handles both with the csv and json modules — no installs needed.
CSV basics#
A CSV file is a table in plain text: one row per line, fields separated by commas, usually with a header row. Fields that contain commas or quotes are wrapped in double quotes:
You could split each line on commas — but "Smith, John" shows why you shouldn't. The csv module handles quoting, escaping and line endings correctly.
Reading CSV with DictReader#
csv.DictReader uses the header row as keys and gives you each row as a dict:
Two important details:
- Open CSV files with
newline="", as thecsvdocs require. It prevents blank lines between rows on Windows and broken multi-line fields. - Every value is a string. CSV has no types, so convert numbers and dates yourself.
The plain csv.reader yields each row as a list of strings instead — useful for files without headers:
Writing CSV#
csv.DictWriter writes dicts; it quotes fields automatically when needed:
Notice how the comma and the inner quotes were escaped for you. Use csv.writer with writerow([...]) for lists.
Dialects and Excel
Some files use semicolons or tabs. Pass delimiter=";" or delimiter="\t" to the reader/writer. For CSVs that Excel should open with non-English characters intact, write with encoding="utf-8-sig" (it adds a byte-order mark Excel looks for). For large or messy spreadsheets, pandas (pd.read_csv) is often more convenient — see the data analysis lesson.
JSON basics#
JSON looks almost exactly like Python literals:
The four functions to remember:
json.dumps(obj)→ JSON string;json.loads(text)→ Python object.json.dump(obj, file)→ write to a file;json.load(file)→ read from a file.
Reading and writing JSON files#
ensure_ascii=False writes non-English characters as-is instead of \u0941-style escapes, which keeps files human-readable.
Handling invalid JSON#
Real-world input is messy. json.loads raises json.JSONDecodeError (a subclass of ValueError) with the exact position of the problem:
Common JSON gotchas: no trailing commas, no comments, strings must use double quotes, and keys must be strings (json.dumps({1: "a"}) turns the key into "1").
Serialising custom types#
json only understands the basic types. Dates, Decimal, sets and your own classes need converting:
The default function is called for any object json doesn't know how to handle. When loading, convert back explicitly (e.g. datetime.fromisoformat(...)), or use a validation library such as Pydantic.
Worked example: CSV → JSON report#
A typical task: read a CSV export, aggregate it, and produce JSON for a dashboard or API.
JSON Lines#
For logs and big datasets you'll often see JSON Lines (.jsonl): one JSON object per line. It can be processed line by line without loading everything:
Common mistakes#
- Splitting CSV lines on commas manually — quoted fields break it. Use
csv. - Forgetting that CSV values are strings — convert before doing maths.
- Missing
newline=""when opening CSV files. - Confusing
load/loadsanddump/dumps. - Using
eval()to parse JSON — never; it executes code. Usejson.loads. - Storing money as JSON floats — use strings or integer paise.
What's next#
Our functions and dataclasses have been sprinkled with annotations like list[str] and -> float. Next lesson: type hints — how to write them and how tools use them to catch bugs before you run your code.
Check your understanding
Quick quiz
1.Why should you open CSV files with
newline=""?2.What is the difference between
json.loadandjson.loads?3.What happens with
json.dumps({"when": datetime.now()})?
Finished reading?
Mark this lesson complete to track your progress.