Using input function
In this section, you'll see how to read a file containing questions, choices and the answer. Then using these details, you'll use input()
function to interactively accept user's choice for each question. At the end, you'll display how many questions were correctly answered.
Two solutions are presented in this section. First one follows the same order as present in the input file and the second one randomizes the order of questions and choices.
File format
To be able to parse the text file, a consistent format is needed to separate out questions, choices and the correct answer for that particular question. Here's one possible structure:
# only first two question blocks are shown here
# there are total five such blocks
$ cat question_and_answers.txt
1) Which of these programming paradigms does Python support?
a) structured
b) object-oriented
c) functional
--> d) all of these choices
2) How would you specify literal characters { and } in f-strings?
--> a) {{ and }} respectively
b) \{ and \} respectively
Each block starts with a number, followed by )
, a space and then the entire question in a single line. This is followed by two or more choices, with each choice on its own line. The choices start with an alphabet, followed by )
, a space and then the text for that choice. There's only one possible answer for this implementation, marked by -->
at the beginning of a choice.
Exactly one empty line marks the end of a question block (including the final question block).
Linear implementation
Here's one possible implementation that maintains the same order of questions and choices.
# mcq_input.py
print('When prompted for an answer, type only the alphabet\n')
ip_file = 'question_and_answers.txt'
total_questions = 0
correct_answers = 0
with open(ip_file) as ipf:
for line in ipf:
if line.startswith('--> '):
answer = line[4]
line = line[4:]
total_questions += 1
print(line, end='')
if line == '\n':
usr_ip = input('Enter you answer: ')
if usr_ip == answer:
correct_answers += 1
print('Correct answer!')
else:
print(f'Oops! The right choice is: {answer}')
print('-' * 50 + '\n')
print(f'You answered {correct_answers}/{total_questions} correctly.\n')
Here's an overview of the logic used in the above program:
- First, inform the user that only the alphabet of the choices presented is required when prompted to answer a question
- The variables
total_questions
andcorrect_answers
track how many question blocks are present in the given input file and the correct answers provided by the user respectively - If a line starts with
-->
- store the answer alphabet
- remove this indicator
- increment the question counter
- If a line is empty,
- ask for user's choice using the
input()
function - compare the user input against the answer saved earlier
- increment the answer counter if user's choice is correct
- also, inform the user whether the choice was correct or not
- ask for user's choice using the
- Finally, give a summary of correct answers and total questions
Here's a sample program execution. The string ...
indicates portion that has been excluded from the output shown.
$ python3.9 mcq_input.py
When prompted for an answer, type only the alphabet
1) Which of these programming paradigms does Python support?
a) structured
b) object-oriented
c) functional
d) all of these choices
Enter you answer: d
Correct answer!
--------------------------------------------------
2) How would you specify literal characters { and } in f-strings?
a) {{ and }} respectively
b) \{ and \} respectively
Enter you answer: b
Oops! The right choice is: a
--------------------------------------------------
...
You answered 4/5 correctly.
Randomizing questions and choices
The random
module will be used here to shuffle the order of the questions and choices.
# mcq_random.py
import random
print('When prompted for an answer, type only the alphabet\n')
ip_file = 'question_and_answers.txt'
question_blocks = open(ip_file).read().rstrip().split('\n\n')
random.shuffle(question_blocks)
total_questions = 0
correct_answers = 0
for block in question_blocks:
total_questions += 1
question, *choices = block.split('\n')
random.shuffle(choices)
print(f'{total_questions}) {question[question.find(" ")+1:]}')
for choice, option in zip(choices, 'abcdefghij'):
if choice.startswith('--> '):
choice = choice[4:]
answer = option
print(f'{option}) {choice[choice.find(" ")+1:]}')
usr_ip = input('\nEnter you answer: ')
if usr_ip == answer:
correct_answers += 1
print('Correct answer!')
else:
print(f'Oops! The right choice is: {answer}')
print('-' * 50 + '\n')
print(f'You answered {correct_answers}/{total_questions} correctly.\n')
Here's an overview of the logic used in the above program:
- The input file is assumed to be small enough to be processed as a single string
rstrip()
method is used to remove excess whitespaces at the end of the filesplit('\n\n')
consecutive newlines is used to get the question blocks- these question blocks are then randomized using
random.shuffle()
- Each question block has the question followed by choices. This is separated out by splitting on
\n
character- sequence unpacking is used to save the question in a string variable and choices as a list of strings
- choice list is then randomized
- Since the questions and choices are randomized, already present question number and choice alphabet cannot be used
- these are removed by finding the index of first space character and slicing syntax
total_questions
already tracks the number of questions, so this is used in place of the deleted question number- The
zip()
function is used on the list of choices and a string of first 10 alphabets (assuming max of 10 choices) to get the choice alphabetzip()
will quit when either of the sequence reaches the end
Here's part of the output for one of the sample runs. Note that both the question and choices have been randomized.
$ python3.9 mcq_random.py
When prompted for an answer, type only the alphabet
1) How would you specify literal characters { and } in f-strings?
a) \{ and \} respectively
b) {{ and }} respectively
Enter you answer: b
Correct answer!
--------------------------------------------------