Editor

Quiz Game in Python

Beginner · Games · about 40 minutes to build · 107 lines

It asks five multiple-choice questions about Python, picked at random from a bank of ten, and gives your score at the end.

The program

Press Run and answer its questions in the box that appears under the code.

quiz_game.py
"""Python quiz: answer multiple-choice questions and get a score at the end."""
import random
QUESTIONS_PER_GAME = 5
LETTERS = "ABCD"
# Each question lists its correct answer first; the options are shuffled when asked.
QUESTIONS = [
{"question": 'What does len("hello") return?',
"options": ["5", "4", "6", "hello"]},
{"question": "Which keyword starts a function definition?",
"options": ["def", "function", "func", "define"]},
{"question": "What is the value of 7 // 2?",
"options": ["3", "3.5", "4", "1"]},
{"question": "Which of these types can be changed after it is created?",
"options": ["list", "tuple", "str", "int"]},
{"question": "What does type(3.0) return?",
"options": ["<class 'float'>", "<class 'int'>", "<class 'str'>", "<class 'double'>"]},
{"question": "Which character starts a comment in Python?",
"options": ["#", "//", "--", "/*"]},
{"question": 'What is the result of "ab" * 3?',
"options": ["ababab", "ab3", "an error", "ab ab ab"]},
{"question": "Which list method adds one item to the end of a list?",
"options": ["append()", "add()", "insert()", "push()"]},
{"question": "Which numbers does range(3) give?",
"options": ["0, 1, 2", "1, 2, 3", "0, 1, 2, 3", "3"]},
{"question": 'What is bool("") (an empty string)?',
"options": ["False", "True", "None", "an error"]},
]
def ask_choice(prompt, valid):
"""Ask until the player types one of the valid letters, and return it."""
while True:
answer = input(prompt).strip().upper()
if answer in valid:
return answer
print(f" Please type one of: {', '.join(valid)}.")
def ask_question(number, item):
"""Ask one question with shuffled options; return True if answered right."""
correct = item["options"][0]
options = item["options"].copy()
random.shuffle(options)
print(f"\nQuestion {number}. {item['question']}")
for letter, option in zip(LETTERS, options):
print(f" {letter}) {option}")
answer = ask_choice("Your answer (A-D): ", list(LETTERS))
right_letter = LETTERS[options.index(correct)]
if answer == right_letter:
print(" Correct.")
return True
print(f" Not quite. The answer is {right_letter}) {correct}.")
return False
def grade(score, total):
"""Return a short message for the final score."""
if score == total:
return "A perfect score."
if score / total >= 0.6:
return "Well done."
return "Keep practising and try again."
def play_quiz():
"""Ask QUESTIONS_PER_GAME random questions and print the result."""
chosen = random.sample(QUESTIONS, QUESTIONS_PER_GAME)
score = 0
for number, item in enumerate(chosen, start=1):
if ask_question(number, item):
score += 1
total = len(chosen)
print(f"\nYou scored {score} out of {total} ({score / total:.0%}).")
print(grade(score, total))
def ask_yes_no(prompt):
"""Ask a yes/no question and return True for yes."""
while True:
answer = input(prompt).strip().lower()
if answer in ("y", "yes"):
return True
if answer in ("n", "no"):
return False
print(" Please type y or n.")
def main():
"""Run quizzes until the player wants to stop."""
print("=== Python Quiz ===")
print(f"{QUESTIONS_PER_GAME} questions. Type the letter of your answer.")
while True:
play_quiz()
print()
if not ask_yes_no("Play again? (y/n) "):
break
print("Thanks for playing.")
if __name__ == "__main__":
main()

Open it in the full editor to save it, share it and keep building.

Sample run

What the program printed, and what was typed (in yellow).

=== Python Quiz ===
5 questions. Type the letter of your answer.

Question 1. Which character starts a comment in Python?
  A) //
  B) /*
  C) --
  D) #
Your answer (A-D): d
  Correct.

Question 2. What is the value of 7 // 2?
  A) 3.5
  B) 3
  C) 1
  D) 4
Your answer (A-D): e
  Please type one of: A, B, C, D.
Your answer (A-D): B
  Correct.

Question 3. What is the result of "ab" * 3?
  A) ab ab ab
  B) an error
  C) ababab
  D) ab3
Your answer (A-D): d
  Not quite. The answer is C) ababab.

Question 4. What is bool("") (an empty string)?
  A) None
  B) False
  C) True
  D) an error
Your answer (A-D): b
  Correct.

Question 5. What does len("hello") return?
  A) 6
  B) hello
  C) 5
  D) 4
Your answer (A-D): c
  Correct.

You scored 4 out of 5 (80%).
Well done.

Play again? (y/n) n
Thanks for playing.

How it is built

1. The question bank

Each question is a dictionary with its text and four options. The correct answer is always written first, which keeps the bank easy to check, and the program shuffles the options before showing them.

# Each question lists its correct answer first; the options are shuffled when asked.
QUESTIONS = [
    {"question": 'What does len("hello") return?',
     "options": ["5", "4", "6", "hello"]},
    {"question": "Which keyword starts a function definition?",
     "options": ["def", "function", "func", "define"]},

2. Accepting only A to D

The answer is turned into a capital letter with .upper(), so a and A both count. Anything else gets a message and the question waits for a valid letter.

def ask_choice(prompt, valid):
    """Ask until the player types one of the valid letters, and return it."""
    while True:
        answer = input(prompt).strip().upper()
        if answer in valid:
            return answer
        print(f"  Please type one of: {', '.join(valid)}.")

3. Asking one question

The function remembers the correct option before it shuffles a copy of the list. zip(LETTERS, options) pairs each option with A, B, C or D, and options.index(correct) finds the letter the answer landed on.

def ask_question(number, item):
    """Ask one question with shuffled options; return True if answered right."""
    correct = item["options"][0]
    options = item["options"].copy()
    random.shuffle(options)

    print(f"\nQuestion {number}. {item['question']}")
    for letter, option in zip(LETTERS, options):
        print(f"  {letter}) {option}")
    answer = ask_choice("Your answer (A-D): ", list(LETTERS))

    right_letter = LETTERS[options.index(correct)]
    if answer == right_letter:
        print("  Correct.")
        return True
    print(f"  Not quite. The answer is {right_letter}) {correct}.")
    return False

4. A message for the score

The checks go from the best score down, so the first one that matches decides the message.

def grade(score, total):
    """Return a short message for the final score."""
    if score == total:
        return "A perfect score."
    if score / total >= 0.6:
        return "Well done."
    return "Keep practising and try again."

5. Picking the questions

random.sample picks five different questions, so none repeats within a game. {score / total:.0%} turns 4 out of 5 into 80%.

def play_quiz():
    """Ask QUESTIONS_PER_GAME random questions and print the result."""
    chosen = random.sample(QUESTIONS, QUESTIONS_PER_GAME)
    score = 0
    for number, item in enumerate(chosen, start=1):
        if ask_question(number, item):
            score += 1

    total = len(chosen)
    print(f"\nYou scored {score} out of {total} ({score / total:.0%}).")
    print(grade(score, total))

Make it bigger

  • Load the questions from a JSON file so a teacher can write a new quiz without touching the code.
  • Time each answer with time.time() and give bonus points for fast ones.
  • At the end, list the questions the player missed with their right answers.
  • Let the player pick a topic, such as strings, lists or loops, before the quiz starts.

What it practises