Working with Data

Python Intermediate — Working with Data
Python Intermediate
Course 2 · Chapter 7 · Working with Data

🗃️ Working with Data

Real programs constantly move data in and out of a program — to a file, an API, a spreadsheet. This chapter covers the three tools you'll reach for most: the json module for JSON data, the csv module for spreadsheet-style data, and a deeper look at datetime, which you saw briefly in Course 1, Chapter 9.

📋 JSON

import json person = {"name": "Ada", "age": 28, "active": True} json_string = json.dumps(person) # Python dict → JSON string print(json_string) # {"name": "Ada", "age": 28, "active": true} parsed = json.loads(json_string) # JSON string → Python dict print(parsed["name"]) # Ada # reading/writing JSON files directly: with open("person.json", "w") as f: json.dump(person, f) # note: dump (file), not dumps (string) with open("person.json", "r") as f: loaded = json.load(f)

JSON's types map onto Python's fairly directly: JSON objects become dicts, arrays become lists, true/false become True/False, and null becomes None. dumps/loads (with an "s", for "string") convert to and from a Python string; dump/load (no "s") read and write a file directly.

⚠ json.dumps() Can't Serialize Every Python Type
import datetime data = {"created": datetime.date.today()} json.dumps(data) # TypeError: Object of type date is not JSON serializable

JSON only understands strings, numbers, booleans, null, objects, and arrays — a Python date object (or any other custom type) has no direct JSON equivalent. The fix is to convert it to a string first (e.g. str(datetime.date.today()) or .isoformat()) before serializing, or pass a custom default= function to json.dumps() that tells it how to convert non-standard types.

📊 CSV

import csv # writing rows as plain lists: with open("scores.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["name", "score"]) writer.writerow(["Alice", 90]) writer.writerow(["Bob", 85]) # reading rows back as plain lists: with open("scores.csv", "r", newline="") as f: reader = csv.reader(f) for row in reader: print(row) # ['name', 'score'], ['Alice', '90'], ['Bob', '85'] # DictReader/DictWriter — rows as dicts, keyed by the header row: with open("scores.csv", "r", newline="") as f: reader = csv.DictReader(f) for row in reader: print(row["name"], row["score"]) # Alice 90, Bob 85

DictReader/DictWriter use the file's header row as dictionary keys — usually more convenient than reader/writer's plain lists, since you access columns by name (row["score"]) instead of by position (row[1]), the same readability trade-off dicts always have over lists.

📅 The datetime Module, Deeper

import datetime now = datetime.datetime.now() # current date AND time (datetime.date.today() is date-only) # formatting a datetime as a string: formatted = now.strftime("%Y-%m-%d %H:%M") print(formatted) # 2026-07-09 14:32 # parsing a string back into a datetime: parsed = datetime.datetime.strptime("2026-01-01", "%Y-%m-%d") # timedelta arithmetic: one_week_later = now + datetime.timedelta(days=7) print((one_week_later - now).days) # 7

strftime ("string format time") turns a datetime into a string using a format code like %Y-%m-%d; strptime ("string parse time") does the reverse, turning a string into a datetime given the format it's in. Adding/subtracting a timedelta — as briefly seen with subtraction in Course 1's own challenge solutions — handles date arithmetic without manually accounting for month lengths or leap years.

Structured Data Serialization: Go vs Kotlin vs Python

LanguageApproach
Goencoding/json maps JSON onto real, statically-typed struct fields using json:"field_name" struct tags — the shape is declared and checked at compile time.
Kotlinkotlinx.serialization (or Gson/Jackson) similarly maps JSON onto typed data class fields, checked by the compiler.
Pythonjson.loads() returns a plain, untyped dict — no schema is declared or checked; a missing or misspelled key only fails at runtime, as a KeyError.

This is a real trade-off worth noticing coming from Go or Kotlin: Python's approach is faster to write and more flexible, but loses the compile-time guarantee that the JSON actually matches the shape your code expects.

json.dumps/loads

Python dict/list ⟷ JSON string; dump/load for files directly.

csv.reader/writer

Rows as plain lists; DictReader/DictWriter for rows as dicts by column name.

strftime / strptime

Format a datetime to a string, or parse a string into a datetime.

timedelta

Date/time arithmetic that correctly handles month lengths and leap years.

💻 Coding Challenges

Challenge 1: Round-Trip a Dict Through JSON

Given a dict representing a small product (name, price, in_stock), convert it to a JSON string with json.dumps(), then parse that string back into a Python dict with json.loads(), and confirm the round trip produced an equal dict.

Goal: Practice the full dumpsloads round trip and confirm no data was lost.

→ Solution

Challenge 2: CSV Average Score

Given a CSV file with columns name and score, use csv.DictReader to read every row and calculate the average score across all students (remembering that CSV values are read as strings, so each score needs converting to a number first).

Goal: Practice DictReader combined with numeric type conversion, a common real-world CSV gotcha.

→ Solution

Challenge 3: Days Until a Parsed Deadline

Given a deadline as a string, "2026-12-25", use datetime.strptime() to parse it into a date, then calculate and print how many days remain between today and that date.

Goal: Practice strptime parsing combined with date subtraction.

→ Solution

🎯 What's Next

Next chapter: Testing with pytest — assertions, fixtures, parametrize, and a contrast with the built-in unittest module.