Lab 03 — Student Grade Book
Hands-on Lab 45 min Beginner
Objectives
- Use dicts to model student records
- Use lists to store collections of records
- Use sets to track unique categories
- Use
Counterto generate statistics - Use
defaultdictto group students by grade
Step 1 — Create the Grade Book
mkdir ~/python-course/lab-03 && cd ~/python-course/lab-03
Create gradebook.py:
#!/usr/bin/env python3
"""
Lab 03 — Student Grade Book
Demonstrates lists, dicts, sets, and collections module.
"""
from collections import Counter, defaultdict
GRADE_SCALE = [
(90, "A", "Excellent"),
(80, "B", "Good"),
(70, "C", "Satisfactory"),
(60, "D", "Passing"),
(0, "F", "Failing"),
]
def letter_grade(score):
"""Convert numeric score to letter grade."""
for threshold, letter, _ in GRADE_SCALE:
if score >= threshold:
return letter
return "F"
def grade_label(score):
"""Return descriptive label for a score."""
for threshold, _, label in GRADE_SCALE:
if score >= threshold:
return label
return "Failing"
def add_student(gradebook, name, scores):
"""Add a student with a list of scores."""
avg = sum(scores) / len(scores)
gradebook[name] = {
"scores": scores,
"average": round(avg, 2),
"grade": letter_grade(avg),
"label": grade_label(avg),
"highest": max(scores),
"lowest": min(scores),
}
def print_report(gradebook):
"""Print a formatted grade report."""
print("\n" + "=" * 60)
print(f"{'STUDENT GRADE REPORT':^60}")
print("=" * 60)
print(f" {'Name':<18} {'Avg':>6} {'Grade':>6} Status")
print("-" * 60)
for name, data in sorted(gradebook.items(), key=lambda x: x[1]["average"], reverse=True):
print(f" {name:<18} {data['average']:>6.1f} {data['grade']:>6} {data['label']}")
print("=" * 60)
def class_statistics(gradebook):
"""Compute and display class-wide statistics."""
averages = [d["average"] for d in gradebook.values()]
grade_counts = Counter(d["grade"] for d in gradebook.values())
print("\n📊 Class Statistics")
print(f" Students : {len(gradebook)}")
print(f" Class avg : {sum(averages)/len(averages):.1f}")
print(f" Highest avg : {max(averages):.1f}")
print(f" Lowest avg : {min(averages):.1f}")
print(f"\n Grade Distribution:")
for grade in ["A", "B", "C", "D", "F"]:
count = grade_counts.get(grade, 0)
bar = "█" * count
print(f" {grade}: {bar} ({count})")
def group_by_grade(gradebook):
"""Group student names by their letter grade."""
groups = defaultdict(list)
for name, data in gradebook.items():
groups[data["grade"]].append(name)
print("\n📋 Students by Grade:")
for grade in sorted(groups):
print(f" {grade}: {', '.join(sorted(groups[grade]))}")
def find_top_students(gradebook, n=3):
"""Return top N students by average."""
ranked = sorted(gradebook.items(), key=lambda x: x[1]["average"], reverse=True)
print(f"\n🏆 Top {n} Students:")
for i, (name, data) in enumerate(ranked[:n], 1):
print(f" #{i}: {name} — {data['average']:.1f} ({data['grade']})")
def subjects_passed(gradebook, passing=60):
"""Show which students have no failing scores."""
print(f"\n✅ Students with all scores ≥ {passing}:")
for name, data in gradebook.items():
all_passed = all(s >= passing for s in data["scores"])
if all_passed:
print(f" {name}")
def main():
gradebook = {}
students_data = [
("Alice Martin", [92, 88, 95, 91, 87]),
("Bob Nguyen", [78, 82, 75, 80, 79]),
("Charlie Smith", [65, 70, 68, 72, 66]),
("Diana Tremblay", [55, 48, 60, 52, 58]),
("Eve Wilson", [98, 97, 99, 96, 98]),
("Frank Dubois", [83, 79, 85, 88, 81]),
("Grace Kim", [72, 68, 74, 70, 73]),
("Henry Lavoie", [45, 50, 42, 55, 48]),
("Isabelle Roy", [91, 93, 89, 95, 92]),
("Jack Thompson", [76, 80, 77, 74, 78]),
]
for name, scores in students_data:
add_student(gradebook, name, scores)
print_report(gradebook)
class_statistics(gradebook)
group_by_grade(gradebook)
find_top_students(gradebook, n=3)
subjects_passed(gradebook)
# Set demo: unique grades achieved
grades_given = {data["grade"] for data in gradebook.values()}
print(f"\n🎓 Grades awarded: {sorted(grades_given)}")
# Tuple demo: top student as immutable record
top = max(gradebook.items(), key=lambda x: x[1]["average"])
record = (top[0], top[1]["average"], top[1]["grade"])
print(f"\n👑 Top record (immutable): {record}")
if __name__ == "__main__":
main()
Step 2 — Run
python3 gradebook.py
Verification ✅
============================================================
STUDENT GRADE REPORT
============================================================
Name Avg Grade Status
------------------------------------------------------------
Eve Wilson 97.6 A Excellent
Isabelle Roy 92.0 A Excellent
Alice Martin 90.6 A Excellent
...
============================================================
📊 Class Statistics
Students : 10
Class avg : 74.4
...
🏆 Top 3 Students:
#1: Eve Wilson — 97.6 (A)
#2: Isabelle Roy — 92.0 (A)
#3: Alice Martin — 90.6 (A)
Bonus
Add an interactive_mode() that lets the user:
- Add a new student via
input() - Look up any student by name
- Remove a student with
del
Summary
You used:
dictto model complex student records with nested datalistto store multiple score valuesset comprehensionto find unique grades awardedtuplefor an immutable top-student recordCounterto count grade distributiondefaultdict(list)to group students by letter gradesorted()with akey=lambdato rank students