Learning Goals
3 minBy the end of this lesson you can:
- Explain what JSON is and why it's everywhere on the web.
- Read a JSON file into Python with
json.load(). - Write a Python value to a JSON file with
json.dump(). - Convert between JSON strings and Python objects using
loads/dumps. - Pretty-print JSON so a human can actually read it.
Warm-Up · What Is JSON?
5 minJSON stands for JavaScript Object Notation. It's a text format that looks almost exactly like a Python dict. Read this file:
{
"name": "Aisyah",
"age": 13,
"subjects": ["maths", "art", "coding"],
"is_member": true
}Notice three differences from Python:
- Keys are always strings in double quotes — no single quotes, no bare names.
true,falseandnullare lowercase (vs. Python'sTrue,False,None).- No trailing commas.
JSON is the universal "data on the wire" format. Every web API, every config file, every save game uses it. Python ships with a json module that turns JSON text into dicts/lists — and back.
New Concept · json.load and json.dump
14 minFour functions, one rule
The json module gives you four functions. Remember the rule: "s" means string.
json.load(file) → Python value (read from a file) json.dump(value, file) → None (write to a file) json.loads(text) → Python value (read from a string) json.dumps(value) → JSON string (write to a string)
Reading a file
import json with open("student.json") as f: student = json.load(f) print(student) print(student["name"]) print(student["subjects"][0])
{'name': 'Aisyah', 'age': 13, 'subjects': ['maths', 'art', 'coding'], 'is_member': True}
Aisyah
mathsThe JSON file becomes a regular Python dict. true in the file became True in Python — the module handles the type translation for you.
Writing a file
import json scores = {"alice": 90, "bob": 75, "cher": 88} with open("scores.json", "w") as f: json.dump(scores, f, indent=2)
The indent=2 kwarg pretty-prints with two spaces. Without it, you get one cramped line — fine for machines, painful for humans.
Strings instead of files (loads / dumps)
Often the JSON arrives as a string (from an API, from a clipboard paste). Use the "s" versions:
raw = '{"name": "Bob", "age": 12}' person = json.loads(raw) print(person["name"]) # → Bob back_to_text = json.dumps(person) print(back_to_text) # → {"name": "Bob", "age": 12}
What types does JSON understand?
JSON ↔ Python
"text" ↔ str
42, 3.14 ↔ int, float
true/false ↔ True/False
null ↔ None
[...] ↔ list
{...} ↔ dictThat's the whole list. Sets, tuples and custom classes are NOT in there — json.dump will raise TypeError if you try. (You'd convert them to lists/dicts first.)
Worked Example · Save and Reload a Quiz
12 minWe'll build a tiny program that saves quiz results to disk, then reloads them next time it runs. This is how every score-saving app on Earth works.
# quiz_save.py — save and reload a quiz result import json FILE = "results.json" # A run of the quiz result = { "player": "Aisyah", "score": 8, "total": 10, "answers": ["A", "C", "B", "B", "D", "A", "C", "C", "B", "A"], } # Save with open(FILE, "w") as f: json.dump(result, f, indent=2) print(f"Saved to {FILE}") # Reload (pretend a different run of the program) with open(FILE) as f: loaded = json.load(f) print(f"\nReloaded: {loaded['player']} scored {loaded['score']}/{loaded['total']}") print("First three answers:", loaded["answers"][:3])
Sample output
Saved to results.json Reloaded: Aisyah scored 8/10 First three answers: ['A', 'C', 'B']
Open results.json in your editor and you'll see a clean, indented file you could email to a teacher:
{
"player": "Aisyah",
"score": 8,
"total": 10,
"answers": [
"A", "C", "B", "B", "D", "A", "C", "C", "B", "A"
]
}with open mattersThe with block makes sure the file gets closed even if your code crashes mid-write. Forgetting to close a file can leave it half-written and corrupted. Make with a habit.
Try It Yourself
13 minBuild a dict with your name, age and three hobbies. Save it to me.json with indent=2. Open the file in your editor and check it looks neat.
Hint
import json me = {"name": "Ali", "age": 12, "hobbies": ["chess", "coding", "kuih"]} with open("me.json", "w") as f: json.dump(me, f, indent=2)
Write a separate script that reads me.json back, then prints a friendly one-line summary: Ali, 12, likes chess + coding + kuih.
Hint
import json with open("me.json") as f: me = json.load(f) print(f"{me['name']}, {me['age']}, likes {' + '.join(me['hobbies'])}.")
Take any nested dict and prove a round-trip works: dump to a string, load it back, confirm the result == the original.
Hint
import json data = {"team": "Hornets", "players": [{"n": "A", "hp": 10}, {"n": "B", "hp": 8}]} text = json.dumps(data) back = json.loads(text) print(data == back) # → True
JSON round-trips are how programs send data over networks and read it on the other side.
Mini-Challenge · High-Score Hall of Fame
8 minBuild scores_app.py. On each run:
- Try to load existing scores from
scores.json. If the file doesn't exist yet, start with an empty list. - Ask the user for a name and a score (use
input). - Append a new dict
{"name": ..., "score": ...}. - Save the list back to the file.
- Print the top 3 scores, highest first.
Show one possible solution
# scores_app.py — file-backed leaderboard import json from pathlib import Path FILE = Path("scores.json") # 1. Load or start empty if FILE.exists(): with FILE.open() as f: scores = json.load(f) else: scores = [] # 2. Ask user name = input("Name: ").strip() score = int(input("Score: ")) # 3. Append scores.append({"name": name, "score": score}) # 4. Save with FILE.open("w") as f: json.dump(scores, f, indent=2) # 5. Top 3 top = sorted(scores, key=lambda s: s["score"], reverse=True)[:3] print("\n🏆 Hall of Fame") for i, s in enumerate(top, 1): print(f" {i}. {s['name']:<10} {s['score']}")
Non-negotiables: handle the "file doesn't exist yet" case, save with indent, sort by score descending, print top 3. Path.exists() from pathlib is the cleanest way to check.
Recap
3 minJSON is the universal data-on-disk and data-on-the-wire format. Python's json module gives you four functions: load and dump work with files; loads and dumps work with strings. JSON's six types map cleanly to Python — anything else (sets, tuples, custom classes) you convert first. Always pretty-print with indent= when a human will read the file.
Vocabulary Card
- JSON
- Plain-text data format. Looks like a Python dict but with stricter rules.
- json.load(f)
- Read a JSON file and return a Python value.
- json.dump(v, f)
- Write a Python value to a JSON file. Use
indent=2for human-readable output. - loads / dumps
- Same idea, but the source/sink is a string instead of a file.
Homework
4 minBuild contacts.py. It should:
- Load contacts from
contacts.json, or start with three sample contacts if the file doesn't exist. - Print every contact in a numbered list.
- Let the user add a new contact (name, phone, email).
- Save the updated list back to
contacts.jsonwithindent=2.
Sample · contacts.py
# contacts.py — JSON-backed contact list import json from pathlib import Path FILE = Path("contacts.json") SEED = [ {"name": "Ahmad", "phone": "012-3000111", "email": "ahmad@example.com"}, {"name": "Mei", "phone": "012-7411233", "email": "mei@example.com"}, {"name": "Suresh", "phone": "017-2289900", "email": "suresh@example.com"}, ] if FILE.exists(): with FILE.open() as f: contacts = json.load(f) else: contacts = SEED print("📒 Contacts") for i, c in enumerate(contacts, 1): print(f" {i}. {c['name']:<10} {c['phone']:<14} {c['email']}") print("\nAdd a new contact:") new = { "name": input(" name : ").strip(), "phone": input(" phone: ").strip(), "email": input(" email: ").strip(), } contacts.append(new) with FILE.open("w") as f: json.dump(contacts, f, indent=2) print(f"\nSaved. {len(contacts)} contacts in {FILE}.")
Non-negotiables: graceful start when the file doesn't exist, list printed with numbers, all three fields collected, indent=2 when saving.