From a Spreadsheet to an App
Bright Future Coaching Centre has 300 students. The office keeps every student’s test marks in a spreadsheet. Every Sunday, after the weekly test, the results must also appear in the institute’s mobile app, where parents check them. The spreadsheet and the app speak different “languages”, and someone has to translate between them.
The spreadsheet can be saved as a CSV file: plain text with one row per line and commas between the values. The app expects JSON: plain text that looks almost exactly like Python dictionaries and lists. These two formats are everywhere. Banks export statements as CSV, websites send data as JSON, and almost every programming language can read both.
In this lesson you will use Python’s built-in json and csv modules to save data, read it back, work with nested data, calculate averages from a marks sheet and convert CSV into JSON, just like the coaching centre needs.
Each run starts in an empty folder. In the playground, every example first creates the files it needs and then reads them. On your own computer the files stay in your project folder, so you can open them in VS Code or a spreadsheet program.
What Is JSON?
JSON stands for JavaScript Object Notation, but it is not only for JavaScript. It is a simple text format for structured data. If you know Python dictionaries and lists, you can already read it. There are a few small differences:
| JSON | Python |
|---|---|
{"name": "Asha"} (object) | dict |
[1, 2, 3] (array) | list |
"text" (always double quotes) | str |
42, 3.5 | int, float |
true / false | True / False |
null | None |
Python to JSON Text: json.dumps
json.dumps() (“dump string”) turns Python data into JSON text. Two options make the output much nicer:
indent=2puts each item on its own line, indented by 2 spaces, so humans can read it.ensure_ascii=Falsekeeps letters like Hindi, Tamil or the ₹ symbol as they are. Without it, Python writes them as codes like\u092a, which are correct but impossible to read.
import json
student = {
"roll_no": 101,
"name": "प्रिया शर्मा",
"course": "JEE Foundation",
"fees_paid": True,
"scholarship": None,
}
print(json.dumps(student))
print()
print(json.dumps(student, indent=2, ensure_ascii=False))
Compare the two outputs. The first is one long line with the Hindi name turned into codes. The second is clear and readable. Also notice that True became true and None became null.
JSON Text to Python: json.loads
json.loads() (“load string”) does the reverse. It reads JSON text and gives you normal Python dictionaries and lists that you can loop over and index.
import json
# Text that arrived from the institute's app
reply = '{"roll_no": 102, "name": "Arjun Rao", "present": true, "rank": null, "marks": [78, 85, 91]}'
data = json.loads(reply)
print(type(data)) # <class 'dict'>
print(data["name"]) # Arjun Rao
print(data["present"]) # True
print(data["rank"]) # None
print(sum(data["marks"])) # 254
An easy way to remember: the s at the end of dumps and loads means string.
Saving and Reading JSON Files
For files, use the versions without the “s”: json.dump(data, file) writes to an open file and json.load(file) reads from one. Open the file with with open(...) as you learned in the Files lesson, and add encoding="utf-8" so that every language is saved correctly.
import json
results = {
"batch": "NEET Morning",
"toppers": ["Meera", "Kabir", "Sana"],
"average": 82.4,
}
# 1. Save to a file (this creates results.json)
with open("results.json", "w", encoding="utf-8") as f:
json.dump(results, f, indent=2, ensure_ascii=False)
# 2. Read it back, as another program would
with open("results.json", encoding="utf-8") as f:
loaded = json.load(f)
print(loaded["toppers"][0]) # Meera
print(loaded == results) # True
The last line prints True: what came out of the file is exactly what went in. This is how apps remember settings, scores and records between runs.
Nested Data
Real JSON is often nested: dictionaries inside lists inside dictionaries. To reach a value, follow the path one step at a time, from the outside in. For example, batch["teacher"]["name"] means “in batch, take teacher, then take name”.
import json
batch_json = """
{
"batch": "JEE Evening",
"teacher": {"name": "Mr. Iyer", "subject": "Physics"},
"students": [
{"name": "Riya", "marks": {"physics": 88, "maths": 92}},
{"name": "Dev", "marks": {"physics": 67, "maths": 74}}
]
}
"""
batch = json.loads(batch_json)
print("Teacher:", batch["teacher"]["name"])
for student in batch["students"]:
physics = student["marks"]["physics"]
print(f"{student['name']} scored {physics} in Physics")
Lost inside nested data? Print one level at a time, for exampleprint(batch.keys())and thenprint(batch["students"][0]). You will soon see the shape.
CSV Files with csv.writer and csv.reader
A CSV (comma-separated values) file is a table in plain text. The first row is usually the header with column names. You could split lines on commas yourself, but values can contain commas too, like Kavya, R.. The csv module handles this for you by putting such values in quotes.
import csv
rows = [
["roll_no", "name", "maths", "science"],
[101, "Asha", 78, 85],
[102, "Imran", 91, 88],
]
# newline="" stops extra blank lines on Windows
with open("marks.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(rows) # many rows at once
writer.writerow([103, "Kavya, R.", 69, 74]) # one more row
with open("marks.csv", encoding="utf-8") as f:
print(f.read())
with open("marks.csv", newline="", encoding="utf-8") as f:
for row in csv.reader(f):
print(row)
Look at the printed file: the name with a comma is wrapped in quotes, and csv.reader reads it back correctly as one value. Each row comes back as a list of strings, even the numbers.
Always open CSV files with newline="". Without it, files written on Windows can have an empty line after every row.
DictWriter and DictReader
Working with positions like row[2] is easy to get wrong. csv.DictWriter and csv.DictReader let you use column names instead. DictReader uses the header row as keys, so each row becomes a dictionary.
import csv
students = [
{"name": "Asha", "city": "Pune", "maths": 78},
{"name": "Imran", "city": "Lucknow", "maths": 91},
]
with open("students.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["name", "city", "maths"])
writer.writeheader()
writer.writerows(students)
with open("students.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
print(row["name"], "from", row["city"], "scored", row["maths"])
print(type(row["maths"])) # <class 'str'>
Notice <class 'str'>: CSV has no number type, so everything you read is text. Convert with int() or float() before you do maths.
Real-Life Example: Weekly Test Results for the App
Here is the full Sunday job for Bright Future Coaching Centre. The program creates the marks sheet (in real life, the office exports it), reads it, calculates each student’s average, marks who passed (40 or more), saves the results as JSON for the app and prints a summary.
import csv
import json
# Step 1: create the spreadsheet file (normally the office exports it)
sheet = """name,physics,chemistry,maths
Asha Verma,78,82,91
Rohan Das,65,58,72
Fatima Khan,92,88,95
Vikram Singh,35,30,38
"""
with open("test_marks.csv", "w", newline="", encoding="utf-8") as f:
f.write(sheet)
# Step 2: read it and work out each student's average
results = []
with open("test_marks.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
marks = [int(row["physics"]), int(row["chemistry"]), int(row["maths"])]
average = round(sum(marks) / len(marks), 1)
results.append({
"name": row["name"],
"average": average,
"passed": average >= 40,
})
# Step 3: save the results as JSON for the app
with open("results.json", "w", encoding="utf-8") as f:
json.dump({"test": "Weekly Test 7", "results": results}, f, indent=2)
# Step 4: print a summary
for r in results:
status = "Pass" if r["passed"] else "Needs support"
print(f"{r['name']:<14} {r['average']:>5} {status}")
class_average = round(sum(r["average"] for r in results) / len(results), 1)
print("Class average:", class_average)
with open("results.json", encoding="utf-8") as f:
saved = json.load(f)
print("Saved", len(saved["results"]), "results to results.json")
Four steps, about 40 lines, and a job that took someone an hour every week now takes less than a second. This “read CSV, calculate, write JSON” pattern appears in thousands of real offices.
Try these changes:
- Add a fifth student to the
sheettext and run again. - Add a
"grade"key: “A” for an average of 85 or more, “B” for 60 or more, otherwise “C”. - Also save the results as a new CSV file with
DictWriter.
Common Mistakes
- Single quotes in JSON. JSON strings must use double quotes. Python-style single quotes fail:
import json
data = json.loads("{'name': 'Asha'}") # ERROR: JSONDecodeError
Fix: use double quotes inside the JSON text (and single quotes around the Python string):
import json
data = json.loads('{"name": "Asha"}')
print(data["name"]) # Asha
- Doing maths with CSV text.
sum([row["maths"] for row in rows])raises aTypeError, because the values are strings. Fix: convert each one withint()orfloat(). - Mixing up
dumpanddumps.json.dumps(data, f)does not write to the file. Fix: usejson.dump(data, f)for files andjson.dumps(data)for strings. - Expecting every Python type to survive. JSON keys are always strings, so
{1: "Asha"}comes back as{"1": "Asha"}. Tuples come back as lists, and dates cannot be saved at all until you turn them into text first. - Forgetting
newline=""orencoding="utf-8". You get blank rows on Windows or broken Hindi names. Add both every time you open a CSV file.
Practice Task: Fee Register to JSON
The coaching centre’s fee register is a CSV file with one row per payment. Write a program that adds up how much each student has paid and saves the totals as JSON.
- Read
fees.csvwithcsv.DictReader(the starter code creates the file). - Add up the amounts for each student in the
totalsdictionary. Remember to convert toint. - Save
totalstofees_summary.jsonwithindent=2. - Read the JSON file back and print each name with the total, like
Asha: Rs 3000.
import csv
import json
# The fee register (this code creates the file for you)
register = """name,month,amount
Asha,July,1500
Imran,July,1500
Asha,August,1500
Kavya,July,1000
Imran,August,1500
"""
with open("fees.csv", "w", newline="", encoding="utf-8") as f:
f.write(register)
totals = {}
# TODO 1: open fees.csv and read it with csv.DictReader
# TODO 2: add each amount (as an int) to totals[name]
# TODO 3: save totals to fees_summary.json with indent=2
# TODO 4: read fees_summary.json back and print each name and total
Show one possible answer (try it yourself first!)
import csv
import json
register = """name,month,amount
Asha,July,1500
Imran,July,1500
Asha,August,1500
Kavya,July,1000
Imran,August,1500
"""
with open("fees.csv", "w", newline="", encoding="utf-8") as f:
f.write(register)
totals = {}
with open("fees.csv", newline="", encoding="utf-8") as f:
for row in csv.DictReader(f):
name = row["name"]
totals[name] = totals.get(name, 0) + int(row["amount"])
with open("fees_summary.json", "w", encoding="utf-8") as f:
json.dump(totals, f, indent=2)
with open("fees_summary.json", encoding="utf-8") as f:
summary = json.load(f)
for name, total in summary.items():
print(f"{name}: Rs {total}")
# Asha: Rs 3000
# Imran: Rs 3000
# Kavya: Rs 1000
Key Takeaways
- JSON is text that looks like Python dicts and lists; CSV is a table as text, with commas between values.
json.dumpsandjson.loadswork with strings;json.dumpandjson.loadwork with files.- Use
indent=2for readable JSON andensure_ascii=Falseto keep Hindi and other scripts as they are. - Use
csv.DictReaderandcsv.DictWriterto work with column names instead of positions. - Everything read from a CSV file is a string: convert numbers before doing maths.
- Open files with
encoding="utf-8", and CSV files also withnewline="".