Students build a quiz app from a list of question dictionaries, make a Radio input for each question with a loop, mark the answers with feedback, then add a question, a perfect-score message and handling for blanks, and make and user-test a quiz of their own.
Load these into Waypoints Prepare: choose Load URL and paste the copied address, or download the file and import it. In Prepare, the worksheet's Teacher edition shows the answers; the student copy hides them.
Predict and Run 10 min · Investigate 10 min · Modify 15 min · Make 15 min
Read the unit primer first. Each question is a dictionary (q["q"], q["choices"], q["answer"]), introduced here only as far as reading one. The inputs list starts empty and a loop appends a gr.Radio per question; mark takes one parameter per question (a1, a2, a3) and puts them in a list to compare by position. A Radio gives the chosen text, or None when nothing is chosen (the third Modify task). The bug task returns inside the loop, so only the first question is ever marked. The info question points at *answers (any number of inputs as a list) as a stretch. The Make ends with user testing: a classmate takes the quiz.
Marking by position: answers[i] against questions[i]. Ask students to trace i for two questions on paper.
| What you will see | A question to ask | The fix |
|---|---|---|
| The score is never more than 1. | Is return inside the loop? | Move return to after the loop (no indent under for). |
| TypeError: mark() takes 3 positional arguments but 4 were given. | How many questions are there now, and how many parameters? | Add a parameter for the new question, and add it to answers. |
| A right answer is marked wrong. | Does the answer exactly match one of the choices, capitals and spaces included? | Copy the answer text from the choices list. |
One possible solution for each task. Other correct programs are fine.
import gradio as gr
questions = [
{"q": "Which planet is closest to the Sun?", "choices": ["Venus", "Mercury", "Mars"], "answer": "Mercury"},
{"q": "How many legs does a spider have?", "choices": ["6", "8", "10"], "answer": "8"},
{"q": "What is 7 x 8?", "choices": ["54", "56", "64"], "answer": "56"},
{"q": "Which gas do plants take in?", "choices": ["Oxygen", "Carbon dioxide", "Helium"], "answer": "Carbon dioxide"},
]
def mark(a1, a2, a3, a4):
answers = [a1, a2, a3, a4]
score = 0
feedback = ""
for i in range(len(questions)):
q = questions[i]
if answers[i] == q["answer"]:
score = score + 1
feedback = feedback + "Right: " + q["q"] + "\n"
else:
feedback = feedback + "Not quite: " + q["q"] + " The answer is " + q["answer"] + ".\n"
return str(score) + " out of " + str(len(questions)), feedback
inputs = []
for q in questions:
inputs.append(gr.Radio(q["choices"], label=q["q"]))
gr.Interface(
fn=mark,
inputs=inputs,
outputs=[gr.Textbox(label="Score"), gr.Textbox(label="Feedback")],
title="Quick quiz",
).launch()
import gradio as gr
questions = [
{"q": "Which planet is closest to the Sun?", "choices": ["Venus", "Mercury", "Mars"], "answer": "Mercury"},
{"q": "How many legs does a spider have?", "choices": ["6", "8", "10"], "answer": "8"},
{"q": "What is 7 x 8?", "choices": ["54", "56", "64"], "answer": "56"},
]
def mark(a1, a2, a3):
answers = [a1, a2, a3]
score = 0
feedback = ""
for i in range(len(questions)):
q = questions[i]
if answers[i] == q["answer"]:
score = score + 1
feedback = feedback + "Right: " + q["q"] + "\n"
else:
feedback = feedback + "Not quite: " + q["q"] + " The answer is " + q["answer"] + ".\n"
if score == len(questions):
feedback = feedback + "Perfect score!"
elif score == 0:
feedback = feedback + "Have another go."
return str(score) + " out of " + str(len(questions)), feedback
inputs = []
for q in questions:
inputs.append(gr.Radio(q["choices"], label=q["q"]))
gr.Interface(
fn=mark,
inputs=inputs,
outputs=[gr.Textbox(label="Score"), gr.Textbox(label="Feedback")],
title="Quick quiz",
).launch()
import gradio as gr
questions = [
{"q": "Which planet is closest to the Sun?", "choices": ["Venus", "Mercury", "Mars"], "answer": "Mercury"},
{"q": "How many legs does a spider have?", "choices": ["6", "8", "10"], "answer": "8"},
{"q": "What is 7 x 8?", "choices": ["54", "56", "64"], "answer": "56"},
]
def mark(a1, a2, a3):
answers = [a1, a2, a3]
score = 0
feedback = ""
for i in range(len(questions)):
q = questions[i]
if answers[i] is None:
feedback = feedback + "No answer: " + q["q"] + "\n"
elif answers[i] == q["answer"]:
score = score + 1
feedback = feedback + "Right: " + q["q"] + "\n"
else:
feedback = feedback + "Not quite: " + q["q"] + " The answer is " + q["answer"] + ".\n"
return str(score) + " out of " + str(len(questions)), feedback
inputs = []
for q in questions:
inputs.append(gr.Radio(q["choices"], label=q["q"]))
gr.Interface(
fn=mark,
inputs=inputs,
outputs=[gr.Textbox(label="Score"), gr.Textbox(label="Feedback")],
title="Quick quiz",
).launch()
import gradio as gr
questions = [
{"q": "Which instrument has 88 keys?", "choices": ["Piano", "Organ", "Accordion"], "answer": "Piano"},
{"q": "How many strings does a violin have?", "choices": ["4", "5", "6"], "answer": "4"},
{"q": "Which family is the trumpet in?", "choices": ["Woodwind", "Brass", "Percussion"], "answer": "Brass"},
{"q": "What does forte mean?", "choices": ["Loud", "Soft", "Fast"], "answer": "Loud"},
]
def mark(a1, a2, a3, a4):
answers = [a1, a2, a3, a4]
score = 0
feedback = ""
for i in range(len(questions)):
q = questions[i]
if answers[i] == q["answer"]:
score = score + 1
else:
feedback = feedback + q["q"] + " The answer is " + q["answer"] + ".\n"
return str(score) + " out of " + str(len(questions)), feedback
inputs = []
for q in questions:
inputs.append(gr.Radio(q["choices"], label=q["q"]))
gr.Interface(fn=mark, inputs=inputs, outputs=[gr.Textbox(label="Score"), gr.Textbox(label="To learn")], title="Music quiz").launch()
Open task: any program that does what the step asks.
Stretch: def mark(*answers): to accept any number of questions, or shuffle each question's choices (import random; random.shuffle).
Support: Give students a fourth question dictionary written out, and ask them only to change the parameters to match.
Why keep the questions in a list instead of writing each Radio by hand?
One loop makes the inputs and one loop marks them, so adding a question means adding data, not new code.
The optional next lesson stores each question as an object with a check method. Machine learning with Gradio (coming later) puts a trained model behind the same kind of app.