Refactor ask_question
Update ask_question to accept a question dict instead of six separate arguments
Writing code and entering commands is only available on desktop. Open this page on a larger screen to complete this chapter.
QUESTIONS is now a list of dictionaries — the data format has been updated for you. Each dict has four fields:
"text"— the question string"options"— a list of four answer strings"correct"— the number of the correct option (1–4)"category"— the topic this question belongs to, such as"loops"or"functions"
The "category" field is new. It lets players filter the quiz to a single topic — for example, practice only "loops" questions before a test. You will wire that up in the next chapter. For now, the field is there in the data; you do not need to use it yet.
The for loop in run_quiz already uses for q in questions_for_round:, so each question arrives as a full dict.
The current ask_question call passes each field individually:
ask_question(q["text"], q["options"][0], q["options"][1], q["options"][2], q["options"][3], q["correct"])That's six arguments extracted from a dict you already have. There is no need to unpack it — pass q directly and let the function access the fields it needs.
This is a common refactoring pattern: when a function receives many related values that all come from the same object, pass the object instead. The function signature shrinks, the call site shrinks, and adding a new field to the dict later does not require updating the signature.
Instructions
Update ask_question to accept the full question dictionary.
- Change the
ask_questionsignature fromdef ask_question(text, o1, o2, o3, o4, correct):todef ask_question(q):— the function now receives the whole question dict. - Inside
ask_question, replace each parameter reference with the corresponding dict lookup:print(text)→print(q["text"])print(f" 1) {o1}")throughprint(f" 4) {o4}")→print(f" 1) {q['options'][0]}")throughprint(f" 4) {q['options'][3]}")is_correct = answer == correct→is_correct = answer == q["correct"]print(f"Wrong! The correct answer was option {correct}.")→print(f"Wrong! The correct answer was option {q['correct']}.")
- In
run_quiz, replace the longask_question(q["text"], q["options"][0], ...)call withask_question(q).
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"},
]
# Step 1: Change signature to ask_question(q)
# Step 2: Replace all parameter references with dict lookups
def ask_question(text, o1, o2, o3, o4, correct):
print(text)
print()
print(f" 1) {o1}")
print(f" 2) {o2}")
print(f" 3) {o3}")
print(f" 4) {o4}")
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 == correct
print()
print(f"You answered: {answer}")
if is_correct:
print("Correct!")
else:
print(f"Wrong! The correct answer was option {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:
# Step 3: Replace the long call with ask_question(q)
result = ask_question(q["text"], q["options"][0], q["options"][1], q["options"][2], q["options"][3], q["correct"])
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:
try:
num_input = input(f"How many questions? (1-{len(QUESTIONS)}, enter for all): ").strip()
if num_input:
num = int(num_input)
else:
num = len(QUESTIONS)
except ValueError:
num = len(QUESTIONS)
print()
run_quiz(num=num)
print()
again = input("Play again? (y/n): ")
if again != "y":
break
print("Thanks for playing!")
Interactive Code Editor
Sign in to write and run code, track your progress, and unlock all chapters.
Sign In to Start Coding