# Simple multiple choice quiz

Posted on

Problem

Just wondering if there’s anything I can improve on, I just started with Python recently and this is one of my first programs.

``````# Defining Score variables
x = 0
score = x

# Question One
print("What is 1 + 1")
print("Correct")
x = x + 1
else:
print("Incorrect, 1 + 1 is 2")

# Question Two
print("Who is the 45th president of the United States?")
print("Correct")
x = x + 1
else:
print("Incorrect, The 45th president is Donald Trump")

# Question Three
print("True or False... The Toronto Maple Leafs have won 13 Stanley   Cups?")
print("Correct")
x = x + 1
else:
print("Incorrect")

# Question Four
print("What was the last year the Toronto Maple Leafs won the Stanley   Cup?")
print("Correct")
x = x + 1
else:
print("Incorrect, The last time the Toronto Maple Leafs won the Stanley Cup was 1967")

# Question Five
print("True or False... The current Prime Minister of Canada is Pierre Elliot Tredeau?")
print("Correct")
x = x + 1
else:
print("Incorrect, The current Prime Minster of Canada is Justin Tredeau")

#Total Score
score = float(x / 5) * 100
print(x,"out of 5, that is",score, "%")
``````

Solution

## 1. DRY (Don’t Repeat Yourself)

You should define containers for your questions and answers. This way you can avoid having to repeat the whole logic for every question.

As a first step, I would advise to put all your question texts, answer texts, choice texts and correct answer texts in lists.

Then you can write a function that iterates over these lists (at the same time) and does the actual game. For this you can use `zip`.

``````questions = ["What is 1 + 1",
"Who is the 45th president of the United States?",
"True or False... The Toronto Maple Leafs have won 13 Stanley   Cups?",
"What was the last year the Toronto Maple Leafs won the Stanley   Cup?",
"True or False... The current Prime Minister of Canada is Pierre Elliot Tredeau?"]
":",
"a)1967nb)1955nc)1987nd)1994n:",
":"]
correct_choices = [{"b", "2"},
{"c", "donald trump"},
{"true", "t"},
{"a", "1967"},
{"false", "f"}]
answers = ["1 + 1 is 2",
"The 45th president is Donald Trump",
"",
"The last time the Toronto Maple Leafs won the Stanley Cup was 1967",
"The current Prime Minster of Canada is Justin Tredeau"]

def quiz():
score = 0
print(question)
print("Correct")
score += 1
else:
print(score, "out of", len(questions), "that is", float(score / len(questions)) * 100, "%")

if __name__ == "__main__":
quiz()
``````

## 2. OOP (Object-Oriented Programming)

A second step could be trying to encapsulate this whole object of a question into an actual Python object. That is, a question is an object that has a question(text), an answer, answer choices and correct answer choices.

You could define a `class` like this:

``````class Question:
def __init__(self, question, answer, choices, correct):
self.question = question
self.choices = choices
self.correct = correct
``````

But this class would be nothing but a data storage for these strings. Whenever you have this, you can use a `collections.namedtuple`.

``````>>> from collections import namedtuple
>>> Question = namedtuple("Question", "question answer choices correct")
>>> q = Question("What is 1 + 1", "1 + 1 is 2", "a)1nb)2nc)3nd)4n:", {"b", "2"})
>>> q.question
'What is 1 + 1'
>>> q
{'b', '2'}
``````

So a `Question` is just a tuple with nice names, so that afterwards `q.question = q = 'What is 1 + 1'`, and so on.

``````from collections import namedtuple
Question = namedtuple("Question", "question answer choices correct")

questions = [Question("What is 1 + 1", "1 + 1 is 2", "a)1nb)2nc)3nd)4n:", {"b", "2"}),
...]

def quiz():
score = 0
for question in questions:
print(question.question)
print("Correct")
score += 1
else:
print(score, "out of", len(questions), "that is",
float(score / len(questions)) * 100, "%")

if __name__ == "__main__":
quiz()
``````

## 3. The last push

Last, but not least, you could make enumerating the choices automatic, using `string.ascii_lowercase` (which is simply the lowercase alphabet) and `str.join`ing it with newlines and the `")"` used to separate a letter from the choice associated with that letter.

You could also pass a list of `Question`s directly to the function, allowing making different quizzes (by choosing randomly 5 questions out of a pool of 100 question, for example).

Finally, you could use `str.format` to make the print of the final score a bit nicer.

``````import string
from collections import namedtuple
Question = namedtuple("Question", "question answer choices correct")

questions = [Question("What is 1 + 1", "1 + 1 is 2",
["1", "2", "3", "4"], {"b", "2"}), ...]

def quiz(questions):
score = 0
for question in questions:
print(question.question)
for line in zip(string.ascii_lowercase, question.choices):
print(") ".join(line))