JSON & CSV

Python · Lesson 32 of 56 6 min read Updated

Plain text files are fine for simple lines, but real data has structure: a student has a name, a city and marks; an order has items and prices. Two text formats are used everywhere to store and exchange such data. JSON is the language of web APIs and settings files. CSV is the language of spreadsheets.

Python's standard library has a module for each: json and csv. In this lesson you will convert Python data to and from both formats and save it in files.

What JSON looks like

JSON (JavaScript Object Notation) is a text format that looks very much like Python dictionaries and lists. A weather API, a mobile app or a settings file might send you text like this:

JSON
{
  "city": "Pune",
  "temperature": 31.5,
  "rain_expected": false,
  "next_days": [30, 29, 33],
  "alert": null
}

JSON has fewer types than Python, so the json module translates between them:

JSONPython
object {...}dict
array [...]list
string "..."str
number 42, 31.5int, float
true / falseTrue / False
nullNone

JSON strings always use double quotes, and keys must be strings.

Converting with dumps() and loads()

json.dumps() (dump to string) turns Python data into JSON text. json.loads() (load from string) does the opposite.

PythonRun it yourself
import json

order = {
    "customer": "Isha",
    "items": ["paneer roll", "lassi"],
    "total": 240,
    "paid": True,
    "coupon": None,
}

text = json.dumps(order)
print(text)
print(type(text))

back = json.loads(text)
print(back["items"][0], back["paid"])
Output
{"customer": "Isha", "items": ["paneer roll", "lassi"], "total": 240, "paid": true, "coupon": null}
<class 'str'>
paneer roll True

Look closely at the JSON text: True became true and None became null. When you load it back, they return to Python values.

Readable output and Indian text

By default dumps() writes everything on one line and replaces characters such as ₹ or Hindi letters with escape codes like \u20b9. Two arguments fix that: indent adds line breaks and spaces, and ensure_ascii=False keeps characters as they are.

PythonRun it yourself
import json

menu = {"shop": "Sharma Sweets", "kaju katli": "₹1,100/kg", "greeting": "नमस्ते"}

print(json.dumps(menu))
print(json.dumps(menu, indent=2, ensure_ascii=False))
Output
{"shop": "Sharma Sweets", "kaju katli": "\u20b91,100/kg", "greeting": "\u0928\u092e\u0938\u094d\u0924\u0947"}
{
  "shop": "Sharma Sweets",
  "kaju katli": "₹1,100/kg",
  "greeting": "नमस्ते"
}

Reading and writing JSON files

json.dump() and json.load(), without the s, work with files instead of strings. Open the file with encoding="utf-8" as you learned in Reading & Writing Files.

PythonRun it yourself
import json
from pathlib import Path

settings_file = Path("settings.json")
settings = {"theme": "dark", "language": "hi", "font_size": 16}

with settings_file.open("w", encoding="utf-8") as f:
    json.dump(settings, f, indent=2, ensure_ascii=False)

with settings_file.open(encoding="utf-8") as f:
    loaded = json.load(f)

loaded["font_size"] += 2
print(loaded)

try:
    json.loads("{'theme': 'dark'}")
except json.JSONDecodeError as error:
    print("Bad JSON:", error)
Output
{'theme': 'dark', 'language': 'hi', 'font_size': 18}
Bad JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)

The last part shows a classic error: single quotes are fine in Python but not in JSON, so loads() raises json.JSONDecodeError. Catch it whenever the JSON comes from a user, a file or the internet.

CSV: comma-separated values

A CSV file is a table stored as text. Each line is a row and commas separate the columns. Excel and Google Sheets open and save CSV files, so it is the easiest way to share tables with non-programmers.

You could split lines on commas yourself, but values that contain commas, such as "Kochi, Kerala", break that approach. The csv module handles quoting for you. Open CSV files with newline="", as the module documentation recommends, so line endings are not doubled on Windows.

PythonRun it yourself
import csv

rows = [
    ["name", "city", "fee"],
    ["Meera", "Kochi, Kerala", 1299],
    ["Rohan", "Lucknow", 999],
]

with open("students.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

with open("students.csv", encoding="utf-8") as f:
    print(f.read())

with open("students.csv", newline="", encoding="utf-8") as f:
    for row in csv.reader(f):
        print(row)
Output
name,city,fee
Meera,"Kochi, Kerala",1299
Rohan,Lucknow,999

['name', 'city', 'fee']
['Meera', 'Kochi, Kerala', '1299']
['Rohan', 'Lucknow', '999']

The writer put quotes around Kochi, Kerala automatically, and the reader removed them. Notice that the fee comes back as the string '1299': CSV has no types, so every value you read is a string.

Rows as dictionaries

csv.DictWriter and csv.DictReader use the header row as keys, so you work with dictionaries instead of remembering column positions.

PythonRun it yourself
import csv

sales = [
    {"item": "Notebook", "qty": 12, "price": 45},
    {"item": "Gel pen", "qty": 30, "price": 10},
    {"item": "Geometry box", "qty": 4, "price": 120},
]

with open("sales.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["item", "qty", "price"])
    writer.writeheader()
    writer.writerows(sales)

total = 0
with open("sales.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        amount = int(row["qty"]) * int(row["price"])
        total += amount
        print(f"{row['item']:<13} ₹{amount}")

print(f"{'Total':<13} ₹{total}")
Output
Notebook      ₹540
Gel pen       ₹300
Geometry box  ₹480
Total         ₹1320

JSON or CSV?

Choose CSV for flat tables where every row has the same columns, especially if someone will open the data in a spreadsheet. Choose JSON for nested data (lists inside dictionaries), settings, and anything you send to or receive from a web API.

Common mistakes

  • Mixing up dump and dumps. The s versions work with strings; the others need a file object.
  • Writing JSON with single quotes by hand. JSON needs double quotes. Let json.dumps() produce the text.
  • Forgetting that CSV values are strings. Convert with int() or float() before doing maths.
  • Leaving out newline="" for CSV files. On Windows you can get a blank line between every row.

Key points

  • json.dumps() and json.loads() convert between Python data and JSON strings; json.dump() and json.load() use files.
  • Use indent=2 for readable JSON and ensure_ascii=False to keep ₹ and Indian scripts as they are.
  • Invalid JSON raises json.JSONDecodeError; sets, dates and custom objects need converting first.
  • The csv module handles quoting; open CSV files with newline="" and encoding="utf-8".
  • DictWriter and DictReader let you work with rows as dictionaries; all values come back as strings.

Exercise

A college canteen in Jaipur keeps its menu as a list of dictionaries with name, price and veg (True or False). Save the menu to menu.json with indentation, load it back, and then write only the vegetarian items to veg_menu.csv with a header row of name,price. Finally, print the contents of the CSV file.

Show solution
Python
import csv
import json
from pathlib import Path

menu = [
    {"name": "Masala dosa", "price": 60, "veg": True},
    {"name": "Chicken roll", "price": 90, "veg": False},
    {"name": "Veg thali", "price": 110, "veg": True},
]

Path("menu.json").write_text(json.dumps(menu, indent=2), encoding="utf-8")
loaded = json.loads(Path("menu.json").read_text(encoding="utf-8"))

with open("veg_menu.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "price"], extrasaction="ignore")
    writer.writeheader()
    writer.writerows(item for item in loaded if item["veg"])

print(Path("veg_menu.csv").read_text(encoding="utf-8"))
Output
name,price
Masala dosa,60
Veg thali,110

extrasaction="ignore" tells DictWriter to skip the veg key, which is not one of the CSV columns. Without it, the writer raises ValueError for the unexpected key.

Quick Quiz

1. What does json.dumps({"ok": True, "note": None}) produce?

2. Which function reads JSON from an open file?

3. You read a CSV row with DictReader and get row["fee"]. What type is it?

4. Why use ensure_ascii=False with json.dumps()?

Learn Python with a mentor

Free lessons get you started. Our Python Programming training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call