Learning Goals
3 minBy the end of this lesson you can:
- Write a function that mixes
input()and a parameter —ask_question(prompt, answer). - Clean the user's reply the same way you clean the correct answer, so capital letters and spaces don't spoil a match.
- Reuse the same function in three calls to run a tiny three-question quiz, with no copy-pasted logic.
Warm-Up
5 minWithout functions, a three-question quiz would look something like this:
a1 = input("What is the capital of Malaysia? ") if a1.strip().lower() == "kuala lumpur": print("Correct!") else: print("Wrong.") a2 = input("What is 7 * 8? ") if a2.strip().lower() == "56": print("Correct!") else: print("Wrong.") a3 = input("What is the chemical symbol for water? ") if a3.strip().lower() == "h2o": print("Correct!") else: print("Wrong.")
Look at that. The same four lines, copy-pasted three times, with only the prompt and the right answer changing. Anything copy-pasted like that is screaming to be put inside a function. Today we do exactly that.
If you find yourself writing the same shape of code with only a couple of values changing, that's a function in disguise. The values that change become the parameters.
New Concept · ask_question(prompt, answer)
14 minSpot what changes vs what stays
From the warm-up, two things change per question — the prompt and the right answer. Everything else is identical. Those two become the parameters:
def ask_question(prompt, answer): reply = input(prompt).strip().lower() if reply == answer.strip().lower(): print("Correct!") return True else: print("Wrong.") return False
Read it line by line:
input(prompt)— the parameterpromptbecomes the question text on screen..strip().lower()on both sides — same hygiene from PY-L1-23. The player can type" Kuala Lumpur "and it still matches.- If they match,
print("Correct!")andreturn True. Otherwiseprint("Wrong.")andreturn False.
Two jobs in one function — fine for a game
In PY-L1-29 we said "one job per function" — compute or display, not both. For a game like this, the function's job is the whole exchange (ask, judge, react), so doing both print and return is reasonable. The return value is for the rest of the program (a score counter); the prints are for the player.
Call it three times
Now the whole quiz is three lines:
ask_question("What is the capital of Malaysia? ", "Kuala Lumpur") ask_question("What is 7 * 8? ", "56") ask_question("What is the chemical symbol for water? ", "H2O")
One function body, three different quizzes. Want to add a fourth question? Add one line. Want to change the "Wrong." message to "Not quite!"? Change it once and all three calls update.
Why we still return a boolean
Even if we don't use the return value right now, returning True or False sets us up for Part 2. Next lesson the main program will look something like:
score = 0 if ask_question("...", "..."): score = score + 1
The boolean drops straight into an if, exactly like is_even from PY-L1-30. Today we just don't use it yet.
Clean both sides the same way
Critical detail. If you only clean the user's reply but not the correct answer, "Kuala Lumpur" won't match "kuala lumpur". Always apply the same chain to both:
reply.strip().lower() == answer.strip().lower()
The teacher can write the answer in any case in the call site; the function takes care of normalising it.
Worked Example · The Three-Question Quiz
13 minThe full file
Save as quiz_engine.py:
Code
# quiz_engine.py — Part 1: ask, judge, react def ask_question(prompt, answer): reply = input(prompt).strip().lower() if reply == answer.strip().lower(): print("✅ Correct!") return True else: print("❌ Wrong. The answer was:", answer) return False # main program print("Welcome to the Hub Quiz!") print("Answer the three questions below.") print("-" * 40) ask_question("Q1. Capital of Malaysia? ", "Kuala Lumpur") ask_question("Q2. 7 × 8? ", "56") ask_question("Q3. Chemical symbol for water? ", "H2O") print("-" * 40) print("Quiz finished. (Scoring comes in Part 2!)")
Sample run · a player who knows their stuff
Welcome to the Hub Quiz! Answer the three questions below. ---------------------------------------- Q1. Capital of Malaysia? kuala lumpur ✅ Correct! Q2. 7 × 8? 56 ✅ Correct! Q3. Chemical symbol for water? H2O ✅ Correct! ---------------------------------------- Quiz finished. (Scoring comes in Part 2!)
Sample run · a sloppy typer
Q1. Capital of Malaysia? KUALA LUMPUR ✅ Correct!
The capitals and extra spaces don't matter — the function cleaned them. That's the same .strip().lower() hygiene from PY-L1-23, just packaged inside a reusable function now.
One quiz, three lines of main program
Look at the three ask_question calls. Each one is a complete question + judgement + reaction, and the entire main program reads like a list of questions. That is the function payoff — your script reads like the thing it does.
Next lesson we'll wrap these calls in a score counter, print encouragement messages ("You're on fire!"), and finish with a percentage. The function we built today won't change — we'll just use what it returns. That's why returning a boolean matters.
Try It Yourself
14 minThree tasks. Build the engine, then customise it.
Open a new file my_quiz.py and type the ask_question function from the worked example exactly. Then call it once with any question of your choice. Run it. Try answering correctly and incorrectly.
Hint
def ask_question(prompt, answer): reply = input(prompt).strip().lower() if reply == answer.strip().lower(): print("✅ Correct!") return True else: print("❌ Wrong. The answer was:", answer) return False ask_question("What is the largest planet in our solar system? ", "Jupiter")
Type jupiter, then try JUPITER, then Jupiter . All three should be marked correct — that's the hygiene chain doing its job.
Add two more calls to ask_question on topics you care about — football, K-pop, dinosaurs, whatever. Aim for three calls total. Run the program and confirm all three questions get asked and judged.
Hint
ask_question("Which player has the most Ballon d'Ors? ", "Messi") ask_question("Which group sang Dynamite? ", "BTS") ask_question("Which dinosaur had three horns? ", "Triceratops")
Notice the main program is just three lines. The interesting stuff (the cleaning, the comparison, the reaction) all lives inside one place — the function definition. Change the function once and all three questions update.
Take one of your calls and store the return value in a variable. After the question, print You got it right! if the return was True, otherwise print Try again next time.. (Yes — the function already prints something, but the boolean return lets the main program react too.)
Hint
got_it = ask_question("What is the capital of Japan? ", "Tokyo") if got_it: print("You got it right!") else: print("Try again next time.")
You should see two messages — one from the function (✅ Correct!) and one from the main program. This is exactly the setup that Part 2 will use to count score.
Mini-Challenge · Hafiz's Cheating Quiz
8 minHafiz wrote his own engine. Strange thing — it marks everything as correct. Find the three bugs.
# hafiz_quiz.py — buggy
def ask_question(prompt, answer):
reply = input(prompt)
if reply = answer:
print("Correct")
return True
ask_question("Capital of France? ", "Paris")
ask_question("2 + 2? ", "4")
ask_question("Largest ocean? ", "Pacific")Test it. Even banana as an answer to "2 + 2?" gets called correct. Find the bugs:
- Bug 1.
if reply = answer:uses a single=(assignment). The comparison operator is==. Python will refuse withSyntaxError. - Bug 2. Once you fix Bug 1, no cleaning is applied.
"paris"won't match"Paris". Add.strip().lower()to both sides. - Bug 3. The
return Truesits outside theif, so the function returnsTruefor every call no matter what. Move it inside theifand add a matchingreturn Falsein anelsebranch.
Show one possible fix
# hafiz_quiz.py — fixed def ask_question(prompt, answer): reply = input(prompt).strip().lower() if reply == answer.strip().lower(): print("Correct") return True else: print("Wrong") return False ask_question("Capital of France? ", "Paris") ask_question("2 + 2? ", "4") ask_question("Largest ocean? ", "Pacific")
Bug 3 is the sneakiest. The screen only prints "Correct" when right, but the return value was always True. That would silently break the score counter in Part 2 — the player would get 100% every time without even answering. Place your returns carefully.
Recap
3 minThe Quiz Engine is built around one function — ask_question(prompt, answer) — that takes a question and the right answer, runs the whole exchange, and returns True or False. Once that function exists, the main program collapses into a list of question lines, and everything important happens in one carefully-tested place. The cleaning chain from PY-L1-23 (.strip().lower()) lives inside the function so every caller automatically gets case-insensitive, whitespace-tolerant judging. Next lesson we wrap these calls in a score counter, add encouragement, and print a percentage at the end.
Vocabulary Card
- quiz engine
- The reusable function (or set of functions) that handles asking, judging and reacting — separate from the actual question data.
- prompt
- The exact text shown to the player when asking the question. We pass it as a parameter.
- normalised comparison
- Cleaning both sides of an
==the same way before checking. Stops minor input variations from breaking equality. - boolean return (for control)
- Returning
TrueorFalseso the main program can react — count score, decide messaging, branch. - data-driven program
- A program where the logic lives in functions and the questions/values are just a list. Easy to add data without touching code.
Homework
4 minCreate a new file my_quiz.py — a five-question quiz on a topic you love.
- Define
ask_question(prompt, answer)exactly as in the worked example. - Write a tiny title block in the main program — three
printlines that welcome the player and tell them how many questions there are. - Make exactly five
ask_questioncalls with questions of your choice — football, K-pop, anime, history, geography, anything. - For at least one question, the right answer should contain a capital letter or a space (e.g.
"New York") so you can confirm the cleaning chain works. - Bonus: capture the return of one call into a variable, and after that question print
You started strong.orDon't give up.depending on the boolean.
Bring my_quiz.py next class. In PY-L1-33 we'll bolt on a score, encouragement messages, and a final report — without changing the function we wrote today.
Sample · my_quiz.py
# my_quiz.py — five-question football quiz def ask_question(prompt, answer): reply = input(prompt).strip().lower() if reply == answer.strip().lower(): print("✅ Correct!") return True else: print("❌ Wrong. The answer was:", answer) return False # main program print("==================================") print(" Welcome to the Football Quiz! ") print(" 5 questions. Good luck! ") print("==================================") first = ask_question("Q1. Which country won the 2022 World Cup? ", "Argentina") if first: print("You started strong.") else: print("Don't give up.") ask_question("Q2. Which player has the most career Champions League goals? ", "Cristiano Ronaldo") ask_question("Q3. Which club is based in Manchester, blue half? ", "Manchester City") ask_question("Q4. How many players are on the pitch per team? ", "11") ask_question("Q5. In which year did Liverpool win their last Premier League? ", "2020") print("==================================") print(" Quiz finished. Scoring next class!") print("==================================")
Notice the function is written once, used five times, and never tweaked for different questions. That's the test for whether you really "got" functions. Also notice — "Manchester City" and "Cristiano Ronaldo" survive the cleaning fine because the chain only lower-cases and strips; the words themselves still match.