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.
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 10 min
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.
| What you will see | A question to ask | The fix |
|---|---|---|
| TypeError: ... takes 1 positional argument but 2 were given. | Is self the first parameter of the method? | def check(self, guess):. |
| AttributeError: 'Question' object has no attribute 'points'. | Is points stored in __init__ with self.? | self.points = points in __init__, and pass a value when making each Question. |
| NameError: name 'answer' is not defined, inside a method. | Does the method use self.answer, or just answer? | Use self.answer: the object's own value. |
One possible solution for each task. Other correct programs are fine.
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 hint(self):
return "It starts with " + self.answer[0]
def feedback(self, guess):
if self.check(guess):
return "Right: " + self.text
return "Not quite: " + self.text + " " + self.hint() + "."
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, points):
self.text = text
self.choices = choices
self.answer = answer
self.points = points
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", 1),
Question("How many legs does a spider have?", ["6", "8", "10"], "8", 1),
Question("What is 7 x 8?", ["54", "56", "64"], "56", 2),
]
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 + questions[i].points
lines = lines + questions[i].feedback(answers[i]) + "\n"
total = 0
for q in questions:
total = total + q.points
return str(score) + " out of " + str(total), 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 instrument has 88 keys?", ["Piano", "Organ", "Accordion"], "Piano"),
Question("How many strings does a violin have?", ["4", "5", "6"], "4"),
Question("Which family is the trumpet in?", ["Woodwind", "Brass", "Percussion"], "Brass"),
Question("What does forte mean?", ["Loud", "Soft", "Fast"], "Loud"),
]
def mark(a1, a2, a3, a4):
answers = [a1, a2, a3, a4]
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="Music quiz").launch()
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.
What is self inside a method?
The object the method was called on, so self.answer is that object's own answer.
Gradio's components are classes too. Machine learning with Gradio (coming later) and games with microStudio build on objects.