Keep a quiz's questions as data, make a Radio input for each one with a loop, and write the function that marks the answers and gives feedback.
Quiz apps, flashcards and online tests are all the same idea: questions stored as data, and code that checks the answers.
A quiz is data: each question has its text, its choices and its answer. Here each question is a dictionary, which looks a value up by its name (its key): q["answer"]. The questions are in a list, so a loop can make one Radio input for each (inputs.append(...) adds it to the end of the inputs list), and the marking function can check every answer the same way.
Make your prediction first. Help opens once you've locked it in.
questions = [
{"q": "How many legs does a spider have?", "answer": "8"},
{"q": "What is 7 x 8?", "answer": "56"},
]
answers = ["8", "54"]
score = 0
for i in range(len(questions)):
if answers[i] == questions[i]["answer"]:
score = score + 1
print(score)
The loop compares answers[0] with question 0's answer, then answers[1] with question 1's. How many match?
Run it, answer the questions and press Submit. Get one wrong on purpose and read the feedback. Then change a question's text in the list and run again: the app changes with the data.
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"
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"
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()
One Radio per question.
The chosen text.
A score that stops at 1.
The score is never more than 1, even with every answer right. Click the line that is wrong.
Add a question of your own. What else has to change?
Add a fourth dictionary to the list, then a fourth parameter: def mark(a1, a2, a3, a4): and answers = [a1, a2, a3, a4].
Add a message to the feedback when every answer is right.
Before the return: if score == len(questions): add "Perfect score!" to the feedback.
A question left blank gives None (Python's word for "no value"). Say it was not answered, instead of "Not quite".
A Radio with nothing chosen gives None. Check if answers[i] is None: first, and say the question was not answered.
Add a fourth question.
Run your program. This ticks when your code does all of the above.
Add a message for a perfect score.
Run your program. This ticks when your code does all of the above.
Say which questions were not answered, instead of marking them wrong.
Run your program. This ticks when your code does all of the above.
Make a quiz on something you know well (a sport, a game, a subject, music) with at least four questions and feedback that helps someone learn.
Swap with a classmate. Fix one thing they found confusing.
Make a quiz of at least four questions on your own topic, with a Radio for each made by a loop.
Run your program. This ticks when your code does all of the above.
On a computer this same file is a real quiz app, and a teacher can host it as a Hugging Face Space for the class. The optional next lesson stores each question as an object with its own check method.
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. About 50 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
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.
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.
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.