Courses/Python Mastery/Module 8: Errors & Files
Module 8 · Lesson 425 minBeginner

Working with JSON and CSV

Lesson goal
The two file formats that power real applications — read and write both.

Working with JSON and CSV

Plain text files store sentences. Real applications store structured data — and two formats run the world: JSON (the language of APIs and configs) and CSV (the language of spreadsheets). Python reads and writes both in a few lines.

JSON — dictionaries as files

JSON (JavaScript Object Notation) looks exactly like Python dicts and lists — because it was designed to be universal:

json
{
  "name": "Aarav",
  "age": 16,
  "skills": ["python", "streamlit"],
  "topper": true
}

Python's json module converts between JSON text and Python objects:

JSONPython
object {}dict
array []list
stringstr
numberint / float
true / falseTrue / False
nullNone

Saving data with json.dump

code
import json

student = {
    "name": "Aarav",
    "age": 16,
    "skills": ["python", "streamlit"],
}

with open("student.json", "w") as f:
    json.dump(student, f, indent=2)       # dump = write Python → JSON file

The indent=2 makes the file human-readable (pretty-printed). Open student.json and you'll see neatly formatted JSON.

Loading data with json.load

code
import json

with open("student.json") as f:
    data = json.load(f)                   # load = read JSON file → Python

print(data["name"])          # Aarav
print(data["skills"][0])     # python
print(type(data))            # <class 'dict'> — a real Python dict again!

That's the full round trip: dict → file → dict. The loaded value is a *real* Python dictionary — index it, loop it, modify it, exactly like the ones you've built by hand.

The persistence pattern (the one from the to-do app)

code
import json
import os

FILE = "tasks.json"

def load_tasks():
    if os.path.exists(FILE):              # first run? no file yet
        with open(FILE) as f:
            return json.load(f)
    return []                             # fresh start

def save_tasks(tasks):
    with open(FILE, "w") as f:
        json.dump(tasks, f, indent=2)

# the app loop
tasks = load_tasks()
tasks.append("learn JSON")
save_tasks(tasks)
print(tasks)

Run it twice — the task list grows. This is how apps remember between sessions, and it's the exact pattern from the to-do lesson, now explained fully.

json.dumps / json.loads — strings, not files

The s versions work with strings instead of files (d = dump string, s = load string):

code
text = json.dumps(student, indent=2)     # dict → JSON string
print(text)

back = json.loads(text)                  # JSON string → dict
print(back["name"])

dumps is how you'd send JSON over a network or embed it in an API request.

CSV — the spreadsheet format

CSV (Comma-Separated Values) is what Excel, Google Sheets, and every data export speak:

code
name,age,grade
Aarav,16,A
Diya,15,A
Kabir,16,B

Python's csv module handles the parsing (including the messy edge cases like commas *inside* values):

code
import csv

# Write
with open("students.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["name", "age", "grade"])      # header
    writer.writerow(["Aarav", 16, "A"])
    writer.writerow(["Diya", 15, "A"])

# Read
with open("students.csv") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)          # each row is a list: ['Aarav', '16', 'A']

The newline="" in the write open is a required quirk on some systems — include it by habit. Each row arrives as a list of strings — numbers included, so convert as needed.

DictReader — CSV with named columns

code
import csv

with open("students.csv") as f:
    reader = csv.DictReader(f)          # uses the header row as keys
    for row in reader:
        print(row["name"], "— grade", row["grade"])

DictReader turns each row into a dictionary keyed by the header — no more remembering that column 1 is age. For anything beyond tiny files, prefer it.

Common Errors & Fixes

  • `json.decoder.JSONDecodeError` — the file isn't valid JSON (truncated write, hand-edited badly). The file is corrupted; regenerate it.
  • `KeyError` after json.load — the JSON lacks that key; .get() it or fix the source.
  • CSV rows all in one cell in Excel — you wrote with plain f.write instead of csv.writer; let the module handle commas and quotes.
  • Blank lines between CSV rows — missing newline="" in the open.

  • ✅ Checkpoint

  • Which functions convert dict→file and file→dict? *(json.dump / json.load)*
  • What's json.dumps for? *(Dict → JSON *string*, no file involved)*
  • Why os.path.exists before load? *(First run has no file — return a fresh default)*
  • What does csv.DictReader give you per row? *(A dict keyed by the header names)*
  • Module 8 checkpoint reached — errors handled, files read and written, data persisting.

    Next module: Object-Oriented Python — the mindset behind every big codebase.