Store each question as an object of your own class, Question, with a check method, so each question knows how to mark itself.
Big apps are built from objects that look after themselves: a question that knows its answer and how to give feedback is easier to reuse than loose dictionaries.
Optional. Last lesson each question was a dictionary, and mark did all the work. A class is a kind of object you design yourself: class Question says what every question has (its text, choices and answer, stored as self.text, self.choices, self.answer) and what it can do (its methods: check(guess) and feedback(guess)). Question("What is 7 x 8?", [...], "56") makes one. If you did Objects with turtles, this is the same idea.
Make your prediction first. Help opens once you've locked it in.
class Question:
def __init__(self, text, choices, answer):
self.text = text
self.choices = choices
self.answer = answer
def check(self, guess):
return guess == self.answer
def feedback(self, guess):
if self.check(guess):
return "Right: " + self.text
return "Not quite: " + self.text + " The answer is " + self.answer + "."
q = Question("What is 7 x 8?", ["54", "56", "64"], "56")
print(q.check("54"))
print(q.feedback("56"))
q.check("54") runs the check method for this question, with self being q. What does it compare?
Run it: the same quiz as last lesson, but each question marks itself. Compare mark here with last lesson's.
import gradio as gr
class Question:
def __init__(self, text, choices, answer):
self.text = text
self.choices = choices
self.answer = answer
def check(self, guess):
return guess == self.answer
def feedback(self, guess):
if self.check(guess):
return "Right: " + self.text
return "Not quite: " + self.text + " The answer is " + self.answer + "."
questions = [
Question("Which planet is closest to the Sun?", ["Venus", "Mercury", "Mars"], "Mercury"),
Question("How many legs does a spider have?", ["6", "8", "10"], "8"),
Question("What is 7 x 8?", ["54", "56", "64"], "56"),
]
def mark(a1, a2, a3):
answers = [a1, a2, a3]
score = 0
lines = ""
for i in range(len(questions)):
if questions[i].check(answers[i]):
score = score + 1
lines = lines + questions[i].feedback(answers[i]) + "\n"
return str(score) + " out of " + str(len(questions)), lines
inputs = []
for q in questions:
inputs.append(gr.Radio(q.choices, label=q.text))
gr.Interface(fn=mark, inputs=inputs, outputs=[gr.Textbox(label="Score"), gr.Textbox(label="Feedback")], title="Quick quiz").launch()
import gradio as gr
class Question:
def __init__(self, text, choices, answer):
self.text = text
self.choices = choices
self.answer = answer
def check(self, guess):
return guess == self.answer
def feedback(self, guess):
if self.check(guess):
return "Right: " + self.text
return "Not quite: " + self.text + " The answer is " + self.answer + "."
questions = [
Question("Which planet is closest to the Sun?", ["Venus", "Mercury", "Mars"], "Mercury"),
Question("How many legs does a spider have?", ["6", "8", "10"], "8"),
Question("What is 7 x 8?", ["54", "56", "64"], "56"),
]
def mark(a1, a2, a3):
answers = [a1, a2, a3]
score = 0
lines = ""
for i in range(len(questions)):
if questions[i].check(answers[i]):
score = score + 1
lines = lines + questions[i].feedback(answers[i]) + "\n"
return str(score) + " out of " + str(len(questions)), lines
inputs = []
for q in questions:
inputs.append(gr.Radio(q.choices, label=q.text))
gr.Interface(fn=mark, inputs=inputs, outputs=[gr.Textbox(label="Score"), gr.Textbox(label="Feedback")], title="Quick quiz").launch()
What self is.
Where the rules live now.
A method missing self.
q.check("56") stops with TypeError: Question.check() takes 1 positional argument but 2 were given. Click the line that is wrong.
Add a hint method (such as the answer's first letter) and use it in the feedback, so a wrong answer gets a hint instead of the answer.
def hint(self): return "It starts with " + self.answer[0]
In feedback, use self.hint() instead of giving the answer away.
Give each question a number of points, and make the score add them up (harder questions worth more).
Add points to init (self.points = points), give each Question a points value, and add questions[i].points to the score.
Add a hint method, and use it in feedback instead of giving the answer.
Run your program. This ticks when your code does all of the above.
Give each question its own points, and score by points.
Run your program. This ticks when your code does all of the above.
Rebuild your quiz from last lesson with Question objects, and add something of your own to the class: a hint, points, a topic, or a method that says how hard the question is.
Build a quiz of at least four Question objects, with the app.
Run your program. This ticks when your code does all of the above.
Real apps (and Gradio itself) are built from classes: gr.Radio and gr.Textbox are classes, and each component you made is an object.
An optional lesson. Students rebuild the quiz with a Question class whose objects check answers and give feedback, then add a hint method and points, and rebuild their own quiz with objects. About 45 minutes.
Open the teacher guide: answers, solutions, slides and a worksheet.
Optional: not needed for completing the course. Students who did Objects with turtles have met classes; for others the lesson introduces them briefly. class Question stores each question's text, choices and answer as attributes (self.answer), set in __init__, and has methods check(guess) and feedback(guess). Python passes the object as the first argument of every method, so the first parameter is self (the bug task leaves it out, and the error says it got 2 arguments instead of 1). mark now asks each question to check itself. The info question introduces the idea behind designing with objects: different kinds of question can each have a check method.
What self is inside a method. Ask which question check was called on, and what self.answer is for it.
Stretch: Make a TypedQuestion class with its own check that compares lower-case text, for questions answered in a Textbox.
Support: Give students the hint method written out, and ask them only to use it in feedback.
Gradio's components are classes too. Machine learning with Gradio (coming later) and games with microStudio build on objects.