Python

Modules Data And Errors

Working with CSV & JSON

name,age,city {"name": "Alice", "age": 25, "city": "Boston"}

JrCodex·6 min read

Jr Codex Python Notes

Level: Intermediate Prerequisites: Chapter 2 Time to complete: ~25 minutes


Table of Contents

  1. Why These Two Formats?
  2. Reading CSV Files
  3. Writing CSV Files
  4. DictReader and DictWriter
  5. Reading & Writing JSON
  6. JSON ↔ Python Type Mapping
  7. Handling Malformed Data
  8. Summary & Next Steps

1. Why These Two Formats?

CSV (Comma-Separated Values) and JSON (JavaScript Object Notation) are the two most common formats you'll encounter moving data in and out of Python programs — spreadsheets export CSV, APIs return JSON, and both reappear constantly in the ML/data modules later in this curriculum.

name,age,city              {"name": "Alice", "age": 25, "city": "Boston"}
Alice,25,Boston
Bob,30,NYC                 ← CSV: tabular, row-based           ← JSON: nested, key-value based

2. Reading CSV Files

import csv
 
with open("people.csv", "r", newline="") as file:
    reader = csv.reader(file)
    header = next(reader)          # first row is usually the header
    print(header)                    # ['name', 'age', 'city']
 
    for row in reader:
        print(row)                    # each row is a LIST of strings
                                          # ['Alice', '25', 'Boston']

Note: always pass newline="" when opening a CSV file — it prevents extra blank rows being inserted on some platforms due to how newlines are translated.

Every value comes back as a str, even numbers — you must convert manually:

with open("people.csv", "r", newline="") as file:
    reader = csv.reader(file)
    next(reader)                       # skip header
    for row in reader:
        name, age, city = row
        age = int(age)                   # ✗ CSV has no types — you decide how to parse
        print(f"{name} is {age} years old")

3. Writing CSV Files

import csv
 
rows = [
    ["name", "age", "city"],
    ["Alice", 25, "Boston"],
    ["Bob", 30, "NYC"],
]
 
with open("output.csv", "w", newline="") as file:
    writer = csv.writer(file)
    writer.writerows(rows)          # write all rows at once
 
    # Or one row at a time:
    # writer.writerow(["Charlie", 35, "LA"])

4. DictReader and DictWriter

More convenient than plain reader/writer — rows come back as dictionaries keyed by the header, so you never have to remember column positions.

import csv
 
with open("people.csv", "r", newline="") as file:
    reader = csv.DictReader(file)     # automatically uses the first row as keys
    for row in reader:
        print(row)                       # {'name': 'Alice', 'age': '25', 'city': 'Boston'}
        print(row["name"])                # 'Alice' — access by column NAME, not position
import csv
 
people = [
    {"name": "Alice", "age": 25, "city": "Boston"},
    {"name": "Bob", "age": 30, "city": "NYC"},
]
 
with open("output.csv", "w", newline="") as file:
    fieldnames = ["name", "age", "city"]
    writer = csv.DictWriter(file, fieldnames=fieldnames)
    writer.writeheader()                  # writes the header row
    writer.writerows(people)

Recommendation: default to DictReader/DictWriter for anything beyond a quick script — accessing row["name"] is far more readable and less error-prone than row[0].


5. Reading & Writing JSON

JSON maps closely onto Python's own dicts and lists — the json module converts between JSON text and native Python objects.

import json
 
# Parsing a JSON STRING into Python objects
json_string = '{"name": "Alice", "age": 25, "hobbies": ["reading", "hiking"]}'
data = json.loads(json_string)         # "loads" = load from STRING
print(data)                              # {'name': 'Alice', 'age': 25, 'hobbies': [...]}
print(type(data))                          # <class 'dict'>
print(data["name"])                          # 'Alice'
 
# Converting Python objects INTO a JSON string
person = {"name": "Bob", "age": 30, "active": True}
json_string2 = json.dumps(person)            # "dumps" = dump to STRING
print(json_string2)                            # '{"name": "Bob", "age": 30, "active": true}'
 
# Pretty-printed output
print(json.dumps(person, indent=2))
# Reading/writing directly from/to a FILE (note: no "s" — load/dump, not loads/dumps)
import json
 
with open("data.json", "r") as file:
    data = json.load(file)          # "load" = load from FILE
 
with open("output.json", "w") as file:
    json.dump(data, file, indent=2)   # "dump" = dump to FILE
FunctionDirectionSource/Target
json.loads(s)JSON string → Python objectstring
json.dumps(obj)Python object → JSON stringstring
json.load(file)JSON file → Python objectfile
json.dump(obj, file)Python object → JSON filefile

Memory trick: the "s" versions (loads/dumps) work with strings; the plain versions work with file objects.


6. JSON ↔ Python Type Mapping

import json
 
data = {
    "name": "Alice",       # JSON string  ↔ Python str
    "age": 25,               # JSON number  ↔ Python int/float
    "active": True,            # JSON true    ↔ Python True
    "spouse": None,              # JSON null    ↔ Python None
    "hobbies": ["reading"],        # JSON array   ↔ Python list
    "address": {"city": "Boston"},  # JSON object  ↔ Python dict
}
 
print(json.dumps(data, indent=2))
JSONPython
objectdict
arraylist
stringstr
numberint or float
true / falseTrue / False
nullNone

Important limitation: JSON has no tuple, set, or datetime type — json.dumps will raise a TypeError on a set, and will silently turn a tuple into a JSON array (which comes back as a list, not a tuple, when re-parsed).


7. Handling Malformed Data

Both formats fail loudly, but differently, on bad input — worth knowing before Chapter 4 covers proper exception handling:

import json
 
bad_json = '{"name": "Alice", "age": }'    # missing value — malformed
data = json.loads(bad_json)                   # json.decoder.JSONDecodeError
 
# CSV with a missing column silently produces a shorter row — no error at all!
# Always validate row length or use DictReader, which surfaces this more clearly
# via missing keys (None values) instead of silent misalignment.

Real-world CSV/JSON is rarely perfectly clean — Chapters 4–5 (Exception Handling) build the tools to handle exactly this kind of malformed input gracefully instead of crashing.


8. Summary & Next Steps

Key Takeaways

  • csv.reader/csv.writer work with plain lists; csv.DictReader/csv.DictWriter work with dicts keyed by column name — prefer the Dict versions for readability.
  • Every CSV value comes back as a str — you must convert types (int(), float()) manually.
  • json.loads/json.dumps work with strings; json.load/json.dump work with file objects — the "s" marks the string variant.
  • JSON maps cleanly onto Python's dict/list/str/int/bool/None — but has no native tuple, set, or datetime support.

Concept Check

  1. What's the difference between csv.reader and csv.DictReader?
  2. Why does json.loads('{"age": 25}')["age"] return an int, but every value from csv.reader comes back as a str?
  3. What's the mnemonic for remembering loads/dumps vs load/dump?

Next Chapter

Chapter 4: Exception Handling


Jr Codex — 1-on-1 Personalized Coaching | Back to Module Index