Lesson Complete
Exit

Lesson Complete!

File I/O

You finished the final lesson of Expand PyQuiz. The quiz now loads its question bank from a file, and saves and restores your stats across sessions — close and reopen the script and your history is waiting.

Here is the complete quiz.py:

import json

QUESTIONS_FILE = "questions.json"
STATS_FILE = "stats.json"

def load_questions():
    with open(QUESTIONS_FILE, "r") as f:
        return json.load(f)

def load_stats():
    try:
        with open(STATS_FILE, "r") as f:
            return json.load(f)
    except FileNotFoundError:
        return {
            "games": 0,
            "best_score": 0,
            "best_total": 0,
            "total_correct": 0,
            "total_questions": 0,
        }

QUESTIONS = load_questions()
STATS = load_stats()

def ask_question(q):
    print(q["text"])
    print()
    print(f"  1) {q['options'][0]}")
    print(f"  2) {q['options'][1]}")
    print(f"  3) {q['options'][2]}")
    print(f"  4) {q['options'][3]}")
    print()
    while True:
        answer_text = input("Your answer (1-4): ")
        try:
            answer = int(answer_text)
        except ValueError:
            print("Please enter 1, 2, 3, or 4.")
            continue
        if answer < 1 or answer > 4:
            print("Please enter 1, 2, 3, or 4.")
            continue
        break
    is_correct = answer == q["correct"]
    print()
    print(f"You answered: {answer}")
    if is_correct:
        print("Correct!")
    else:
        print(f"Wrong! The correct answer was option {q['correct']}.")
    return is_correct

def show_results(score, total):
    print(f"Score: {score}/{total}")
    if score == total:
        print("Perfect score!")
    elif score >= 2:
        print("Great job!")
    elif score >= 1:
        print("Not bad!")
    else:
        print("Keep practicing!")

def show_stats():
    if STATS["games"] == 0:
        print("No games played yet.")
        return
    print(f"Games played: {STATS['games']}")
    print(f"Best round: {STATS['best_score']}/{STATS['best_total']}")
    print(f"Total correct: {STATS['total_correct']} out of {STATS['total_questions']}")

def save_stats():
    with open(STATS_FILE, "w") as f:
        json.dump(STATS, f, indent=2)

def run_quiz(questions=QUESTIONS, num=None):
    if num is None:
        num = len(questions)
    score = 0
    streak = 0
    questions_for_round = questions[:num]
    total = len(questions_for_round)
    print(f"=== Python Quiz ({total} questions) ===")
    print()
    for q in questions_for_round:
        result = ask_question(q)
        if result:
            score = score + 1
            streak = streak + 1
            if streak >= 3:
                print(f"  Hot streak! ({streak} in a row)")
        else:
            streak = 0
    show_results(score, total)
    return score, total

while True:
    show_stats()
    print()
    categories = sorted(set(q["category"] for q in QUESTIONS))
    print("Categories: " + ", ".join(categories))
    category = input("Category (enter for all): ").strip()
    if category:
        pool = [q for q in QUESTIONS if q["category"] == category]
        if not pool:
            print("Category not found. Playing all.")
            pool = QUESTIONS
    else:
        pool = QUESTIONS
    try:
        num_input = input(f"How many questions? (1-{len(pool)}, enter for all): ").strip()
        if num_input:
            num = int(num_input)
        else:
            num = len(pool)
    except ValueError:
        num = len(pool)
    print()
    score, total = run_quiz(pool, num)
    STATS["games"] = STATS["games"] + 1
    STATS["total_correct"] = STATS["total_correct"] + score
    STATS["total_questions"] = STATS["total_questions"] + total
    if score > STATS["best_score"]:
        STATS["best_score"] = score
        STATS["best_total"] = total
    print()
    again = input("Play again? (y/n): ")
    if again != "y":
        save_stats()
        break

print("Thanks for playing!")

What you added:

  • load_questions — reads questions.json at startup using json.load(); the question bank lives outside the source file
  • save_stats — writes STATS to stats.json on exit using json.dump(); your history survives the session
  • load_stats — reads stats.json at startup; the try/except FileNotFoundError block handles the first run gracefully, returning an empty stats dict when no file exists yet

The Learn Python from Scratch path is complete.

You built quiz.py from scratch across three courses: a basic quiz, an expanding quiz with categories and stats, and now a full quiz that reads and writes data from disk. Every Python concept you learned — variables, control flow, functions, lists, dicts, sets, and file I/O — is in that file, working together.