3.14 Libraries HW
3.14 Libraries
Source lesson: python/libraries
Learning Objective: Import Python libraries, use their API documentation to call procedures correctly, and read a requirements.txt file.
Submission notes
- Lesson: CSP 3.14 Libraries
- Popcorn 1: what I changed = jersey range 1–99 → 1–55, court area 144 → 2500 sq ft
- Popcorn 2: my extra route = /coach (plus /record)
- Homework: libraries used = json, statistics, datetime, math
- Homework: days until my next game = 16 (printed on the 2026-10-01 run; next game is 2026-10-17)
Popcorn Hack 1: Read the API, Then Use It
Changes: jersey range randint(1, 55) and a 2500 sq ft court instead of 144.
Prediction: the jersey is a random whole number from 1 to 55, and both ends are possible because the randint docs say “including both end points”. math.sqrt(2500) = 50.0 feet (a float, not an int). The average is (24 + 18 + 31 + 27 + 22) / 5 = 24.4, and math.ceil rounds it up to 25. The random game is one of the five values, but which one changes every run.
Code Runner Challenge
Run it, then change the jersey range to 1-55 and predict the new output
View IPYNB Source
# CODE_RUNNER: Run it, then change the jersey range to 1-55 and predict the new output
import math
import random
# Read the API before calling a procedure
print("random.randint:", random.randint.__doc__)
print("math.ceil:", math.ceil.__doc__)
points_per_game = [24, 18, 31, 27, 22]
# random.choice picks one item out of a list
print("Random game to review:", random.choice(points_per_game), "points")
# CHANGED: random.randint(a, b) returns a whole number from a to b, including both
jersey = random.randint(1, 55)
print("Random jersey number:", jersey)
# CHANGED: a 2500 square foot square court
side = math.sqrt(2500)
print("Square court side:", side, "feet")
# math.ceil rounds up to the next whole number
average = sum(points_per_game) / len(points_per_game)
rounded_up = math.ceil(average)
print("Points per game:", average, "-> rounded up:", rounded_up)
Actual output: the side is 50.0 feet, the average is 24.4 → 25, and the jersey and review game are random within their ranges. I left out the dir(math) / dir(random) lines from my copy because they print the full list of names in each library, which is long. I did read those lists while working in the lesson runner.
Popcorn Hack 2: Write a Flask Route
Changed the roster to my own players and added two routes, /coach and /record, above app.test_client().
Code Runner Challenge
Run it, then change the roster and add a route of your own, such as /coach
View IPYNB Source
# CODE_RUNNER: Run it, then change the roster and add a route of your own, such as /coach
from flask import Flask, jsonify
app = Flask(__name__)
# A route is a procedure with a web address attached to it
@app.route("/score")
def score():
return jsonify({"home": 58, "away": 52, "quarter": 3})
@app.route("/roster")
def roster():
return jsonify({"players": ["Ishan", "Maya", "Leo", "Priya", "Jordan"]})
@app.route("/coach")
def coach():
return jsonify({"name": "Coach Rivera", "role": "head coach", "years": 6})
@app.route("/record")
def record():
wins = 7
losses = 3
return jsonify({"wins": wins, "losses": losses, "win_pct": round(wins / (wins + losses), 3)})
# test_client visits the addresses without needing a browser
client = app.test_client()
print("/score says:", client.get("/score").get_json())
print("/roster says:", client.get("/roster").get_json())
print("/coach says:", client.get("/coach").get_json())
print("/record says:", client.get("/record").get_json())
Homework Hack: Season Stats Report
My own version: a soccer forward’s season, counting goals instead of points. It uses four standard library modules:
| Library | Procedure | Used for |
|---|---|---|
statistics |
mean, median |
average and median goals per game |
math |
floor |
rounding minutes-per-goal down to a whole number |
datetime |
date, date.today(), .days |
days until the next game |
json |
dumps(..., indent=2) |
printing the report the way a scoreboard page would receive it |
Code Runner Challenge
Homework - Season Stats Report (soccer)
View IPYNB Source
# CODE_RUNNER: Homework - Season Stats Report (soccer)
import json
import math
import statistics
from datetime import date
games = [
{"date": "2026-09-05", "opponent": "Westview", "goals": 2, "minutes": 80},
{"date": "2026-09-12", "opponent": "Rancho Bernardo", "goals": 0, "minutes": 65},
{"date": "2026-09-19", "opponent": "Westview", "goals": 1, "minutes": 75},
{"date": "2026-09-23", "opponent": "Del Norte", "goals": 3, "minutes": 80},
{"date": "2026-09-30", "opponent": "Mt. Carmel", "goals": 1, "minutes": 70},
]
def summarize_season(season):
"""
Summarize one player's soccer season.
Parameters:
season: list of dictionaries, one per game, each with
"date" (str, YYYY-MM-DD), "opponent" (str),
"goals" (int) and "minutes" (int, minutes played)
Returns:
dictionary with
total_goals (int): goals across every game
average_goals (float): mean goals per game, rounded to 2 places
median_goals (int or float): middle value of goals per game
best_game (dict): {"opponent", "date", "goals"} for the highest-scoring game
goals_by_opponent (dict): opponent name -> total goals against them
minutes_per_goal (int or None): total minutes / total goals, rounded down;
None if no goals were scored
"""
goals = []
total_minutes = 0
goals_by_opponent = {}
best = season[0]
for game in season:
goals.append(game["goals"])
total_minutes += game["minutes"]
opponent = game["opponent"]
goals_by_opponent[opponent] = goals_by_opponent.get(opponent, 0) + game["goals"]
if game["goals"] > best["goals"]:
best = game
total_goals = sum(goals)
return {
"total_goals": total_goals,
"average_goals": round(statistics.mean(goals), 2),
"median_goals": statistics.median(goals),
"best_game": {"opponent": best["opponent"], "date": best["date"], "goals": best["goals"]},
"goals_by_opponent": goals_by_opponent,
"minutes_per_goal": math.floor(total_minutes / total_goals) if total_goals > 0 else None,
}
report = summarize_season(games)
# Subtracting two dates gives a timedelta; .days is the whole number of days
next_game = date(2026, 10, 17)
report["next_game"] = {"opponent": "Torrey Pines", "date": next_game.isoformat()}
report["days_until_next_game"] = (next_game - date.today()).days
print(json.dumps(report, indent=2))
# requirements.txt lists only EXTERNAL packages that must be installed with pip.
# json, math, statistics and datetime are part of Python's standard library,
# so they come with every Python install and are never listed.
requirements_txt = """pandas
Flask
"""
print()
print("requirements.txt:")
print(requirements_txt)
Checking the numbers by hand: goals 2 + 0 + 1 + 3 + 1 = 7. Mean 7 / 5 = 1.4. Sorted [0, 1, 1, 2, 3] gives a median of 1. The best game is Del Norte (3). Westview totals 2 + 1 = 3. Minutes 370 / 7 = 52.86, rounded down to 52. All of these match the printed JSON. days_until_next_game is computed from today’s date each time the cell runs.
requirements.txt: a real version of this app would use pandas for the season table and Flask for the scoreboard page, so both are listed. Standard library modules (json, datetime, math, statistics) ship with Python itself, so pip has nothing to install for them.