patternpythonMinor
Multiple Choice Quiz with Stat Tracking
Viewed 0 times
trackingwithquizchoicestatmultiple
Problem
I was hoping I could get some of you to look over a program I wrote. I am just beginning to learn about Python (for the last month or so). Therefore, I may not be aware of techniques that would make this program better. Currently I'm studying Python 2.7. Any advice or suggestions you could provide would be appreciated. Thanks again.
```
##Flash Card Program
# Import required modules
import random
import sys
import os
import math
# variables
right_answer_total = float(0)
wrong_answer_total = float(0)
percentage = 100 * (float(right_answer_total) / float(answer_total)) if (right_answer_total > 0 and answer_total > 0) else 0
# dictionary containing the information for the questions & answers
word_drills = {'class': 'Tell Python to make a new kind of thing.',
'object': 'Two meanings: the most basic kind of thing, and any instance of some thing.',
'instance': 'What you get when you tell Python to create a class.',
'def': 'How you define a function inside a class.',
'self': 'Inside the functions in a class, self is a variable for the instance/object being accessed.',
'inheritance': 'The concept that one class can inherit traits from another class, much like you and your parents.',
'composition': 'The concept that a class can be composed of other classes as parts, much like how a car has wheels.',
'attribute': 'A property classes have that are from composition and are usually variables.',
'is-a': 'A phrase to say that something inherits from another, as in a Salmon *** Fish',
'has-a': 'A phrase to say that something is composed of other things or has a trait, as in a Salmon *** mouth.'}
# Main portion of the program
def start():
# For loop that creates a list named keys. It grabs 3 random keys from the dictionary word_drills
keys = [x for x in random.sample(word_drills, 3)]
# User is presented with a question. A value from
```
##Flash Card Program
# Import required modules
import random
import sys
import os
import math
# variables
right_answer_total = float(0)
wrong_answer_total = float(0)
percentage = 100 * (float(right_answer_total) / float(answer_total)) if (right_answer_total > 0 and answer_total > 0) else 0
# dictionary containing the information for the questions & answers
word_drills = {'class': 'Tell Python to make a new kind of thing.',
'object': 'Two meanings: the most basic kind of thing, and any instance of some thing.',
'instance': 'What you get when you tell Python to create a class.',
'def': 'How you define a function inside a class.',
'self': 'Inside the functions in a class, self is a variable for the instance/object being accessed.',
'inheritance': 'The concept that one class can inherit traits from another class, much like you and your parents.',
'composition': 'The concept that a class can be composed of other classes as parts, much like how a car has wheels.',
'attribute': 'A property classes have that are from composition and are usually variables.',
'is-a': 'A phrase to say that something inherits from another, as in a Salmon *** Fish',
'has-a': 'A phrase to say that something is composed of other things or has a trait, as in a Salmon *** mouth.'}
# Main portion of the program
def start():
# For loop that creates a list named keys. It grabs 3 random keys from the dictionary word_drills
keys = [x for x in random.sample(word_drills, 3)]
# User is presented with a question. A value from
Solution
Here's a step by step Pythonization walk-trough.
Trivial simplifications
Before:
After:
Reasoning: a single division argument (either numerator or denominator) is sufficient to be of a float type so that the float division was performed.
Before:
After:
Reasoning:
Before:
After:
Reasoning: same effect with less code; variables
Code Refactoring
Looks like you came from functional programming world. Each of your functions ends in calling another function. Since Python has no tail call optimization you will end up in stack overflow eventually.
Thus your algorithm must be revised in a more imperative way. The whole program looks like this:
For the outer loop a
Statistics printing is mostly left intact. The function name changed from
Bearing simplifications in mind and renaming the variables to reflect their meanings in mind here's the question preparation:
Since the whole program resides in a loop there's no need for
Checking the answer for correctness needs a little bit more explanation.
First of all, the
Getting the user's answer is basically inferring an index from
Now figuring out whether user was correct or not is a matter of checking whether
Along with statistics update the code looks like this:
Final Touches
The main entry point function is called
To avoid your program starting when it is imported (as
And here's the whole code:
```
#!/usr/bin/env python
import random
import os
# dictionary containing the information for the questions & answers
word_drills = {'class': 'Tell Python to make a new kind of thing.',
'object': 'Two meanings: the most basic kind of thing, and any instance of some thing.',
'instance': 'What you get when you tell Python to create a class.',
'def': 'How you define a function inside a class.',
'self': 'Inside the functions in a class, self is a va
Trivial simplifications
Before:
answer_total = float(right_answer_total + wrong_answer_total)
percentage = 100 * (float(right_answer_total) / float(answer_total))After:
percentage = 100 * right_answer_total / float(right_answer_total + wrong_answer_total)Reasoning: a single division argument (either numerator or denominator) is sufficient to be of a float type so that the float division was performed.
Before:
keys = [x for x in random.sample(word_drills, 3)]After:
keys = random.sample(word_drills, 3)Reasoning:
[x for x in l] results in a copy of l since neither filtering nor element transformations are performed.Before:
key1, key2, key3 = keys[0], keys[1], keys[2]
print "\n\n(a)%s (b)%s (c)%s" % (key1, key2, key3)
a, b, c = word_drills[key1], word_drills[key2], word_drills[key3]After:
print "\n\n(a)%s (b)%s (c)%s" % tuple(keys)Reasoning: same effect with less code; variables
key1, key2, key3, a, b, c are unnecessary (see below).Code Refactoring
Looks like you came from functional programming world. Each of your functions ends in calling another function. Since Python has no tail call optimization you will end up in stack overflow eventually.
Thus your algorithm must be revised in a more imperative way. The whole program looks like this:
- Repeat in an infinite loop:
- Print statistics
- Prepare a question
- Gather user input
- Exit program if user input was invalid
- Check whether user's answer was correct
- Update answer statistics
For the outer loop a
while True: construction will do.Statistics printing is mostly left intact. The function name changed from
stat_tracking to print_stats to reflect the innards. Note that there is no tail call to start() since this function will be invoked from start() not vice versa. Also, to avoid global variables, stats are passed as paramenters:def print_stats(right_answer_total, wrong_answer_total, percentage):
os.system('cls' if os.name=='nt' else 'clear')
print "-" * 37
print "| Stat Tracking |"
print "-" * 37
print "| Correct | Incorrect | Percentage |"
print "-" * 37
print "| %d | %d | %d %% |" % (right_answer_total, wrong_answer_total, percentage)
print "-" * 37
print "\n\n\n"Bearing simplifications in mind and renaming the variables to reflect their meanings in mind here's the question preparation:
possible_answers = random.sample(word_drills, 3)
correct_answer = random.choice(possible_answers)
question = word_drills[correct_answer]
print "Question:", question
print "\n\n(a)%s (b)%s (c)%s" % tuple(possible_answers)Since the whole program resides in a loop there's no need for
exit()ing, a simple break will do:if selection not in ('a', 'b', 'c'):
print "That is not a valid selection."
breakChecking the answer for correctness needs a little bit more explanation.
First of all, the
answered_correctly() and not_answered_correctly() are gone. They were mostly the same, only a single line differed.Getting the user's answer is basically inferring an index from
possible_answers. Since we validated selection (see above) we are sure that its value is in "a", "b", "c". "a", "b", "c" correspond to 0, 1, 2 indexes of the possible_answers list respectively. Since "a", "b", "c" are laid out sequentially in ASCII table ord(selection) - ord('a') can be used to convert the string to answer index.Now figuring out whether user was correct or not is a matter of checking whether
answer == correct_answer.Along with statistics update the code looks like this:
answer = possible_answers[ord(selection) - ord('a')]
if answer == correct_answer:
print "That's correct!"
right_answer_total += 1
else:
print "I'm sorry, that is incorrect..."
wrong_answer_total += 1
percentage = 100 * right_answer_total / float(right_answer_total + wrong_answer_total)Final Touches
sys and math modules are unused, so do not import them.The main entry point function is called
main() rather then start(). Though that is just a convention.To avoid your program starting when it is imported (as
import program) rather then started as a program (as python program.py) the following trick is used:if __name__ == '__main__':
main()And here's the whole code:
```
#!/usr/bin/env python
import random
import os
# dictionary containing the information for the questions & answers
word_drills = {'class': 'Tell Python to make a new kind of thing.',
'object': 'Two meanings: the most basic kind of thing, and any instance of some thing.',
'instance': 'What you get when you tell Python to create a class.',
'def': 'How you define a function inside a class.',
'self': 'Inside the functions in a class, self is a va
Code Snippets
answer_total = float(right_answer_total + wrong_answer_total)
percentage = 100 * (float(right_answer_total) / float(answer_total))percentage = 100 * right_answer_total / float(right_answer_total + wrong_answer_total)keys = [x for x in random.sample(word_drills, 3)]keys = random.sample(word_drills, 3)key1, key2, key3 = keys[0], keys[1], keys[2]
print "\n\n(a)%s (b)%s (c)%s" % (key1, key2, key3)
a, b, c = word_drills[key1], word_drills[key2], word_drills[key3]Context
StackExchange Code Review Q#14838, answer score: 2
Revisions (0)
No revisions yet.