Lesson Complete!

Dictionaries

You finished the second lesson of Expand PyQuiz. Questions are now dictionaries, and players can filter by category before each round.

Here is the complete quiz.py:

QUESTIONS = [
    {"text": "What is the type of the value 3.14?", "options": ["int", "str", "float", "bool"], "correct": 3, "category": "types"},
    {"text": "What keyword defines a function in Python?", "options": ["for", "def", "if", "class"], "correct": 2, "category": "functions"},
    {"text": "What does print() do?", "options": ["Stores a value", "Returns a number", "Displays output", "Reads input"], "correct": 3, "category": "output"},
    {"text": "What type does input() always return?", "options": ["int", "float", "str", "bool"], "correct": 3, "category": "output"},
    {"text": "Which keyword starts a for loop?", "options": ["loop", "repeat", "for", "each"], "correct": 3, "category": "loops"},
    {"text": "What does len() return?", "options": ["The first item", "The last item", "The number of items", "The sum"], "correct": 3, "category": "basics"},
    {"text": "What is the result of 10 // 3?", "options": ["3.33", "3", "1", "0"], "correct": 2, "category": "basics"},
    {"text": "Which keyword exits a loop early?", "options": ["exit", "return", "stop", "break"], "correct": 4, "category": "loops"},
    {"text": "What does elif stand for?", "options": ["else if", "elif loop", "end loop if", "extra loop"], "correct": 1, "category": "conditionals"},
    {"text": "What does a function return with no return statement?", "options": ["0", "False", "None", "Error"], "correct": 3, "category": "functions"},
]

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 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)

while True:
    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()
    run_quiz(pool, num)
    print()
    again = input("Play again? (y/n): ")
    if again != "y":
        break

print("Thanks for playing!")

What you added:

  • Dict format — each question now has named fields: "text", "options", "correct", "category"
  • ask_question(q) — accepts a single dict instead of six separate arguments
  • Derived category listsorted(set(q["category"] for q in QUESTIONS)) reads categories from the data instead of hardcoding them
  • List comprehension[q for q in QUESTIONS if q["category"] == category] filters by topic
  • pool — the filtered (or full) question list, passed to run_quiz each round

What's still missing: the quiz forgets everything when you quit — your scores, your best round, how many questions you have played in total. In the next lesson, you will use a dictionary to track your stats across every round.