3
\$\begingroup\$

I'm currently in the early stages of a Python project, and the program (so far) asks the user what test they would like to take and what difficulty they would like it to be, and I'd like to know if there're any optimisations that I could make.

class NotWork(Exception): pass
class DoWork(Exception): pass
def which_test(real_dif, real_test, give_test):
 if difficulty == real_dif and test == real_test: 
 give_test()
def is_it_correct(variable, subdif1, subdif2, subdif3, message):
 if variable != subdif1 and variable != subdif2 and variable != subdif3:
 print(message)
 raise NotWork
 else:
 raise DoWork
while True:
 try:
 test = str(input("What test do you want to take? Computer Science, History or Music? ").strip().lower())
 is_it_correct(test, "computer science", "history", "music", """\nSorry, you didn’t input valid settings. Please enter (without the quotes) either "Computer Science", "History", or "Music".\n""")
 except NotWork:
 continue
 except DoWork:
 break
while True:
 try:
 difficulty = str(input("Do you want to take the test in easy, medium or hard? ").strip().lower())
 is_it_correct(difficulty, "easy", "medium", "hard", """\nSorry, you didn't input valid settings. Please enter (without the quotes) either "Easy", "Medium", or "Hard".\n""")
 except NotWork:
 continue
 except DoWork:
 break
which_test("easy", "computer science", easy_CS)
which_test("medium", "computer science", medium_CS)
which_test("hard", "computer science", hard_CS)
which_test("easy", "history", easy_history)
which_test("medium", "history", medium_history)
which_test("hard", "history", hard_history)
which_test("easy", "music", easy_music)
which_test("medium", "music", medium_music)
which_test("hard", "music", hard_music)
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Sep 25, 2017 at 23:43
\$\endgroup\$
0

1 Answer 1

6
\$\begingroup\$

Use of Exceptions/Errors

Raising the DoWork error when input validation succeeds seems strange. Errors are usually raised by a function when, for some reason, it could not do what it was supposed to. Raising an error from is_it_correct if the input was not correct seems like fair game - in fact, there is a built-in ValueError that is meant to be raised when a function is called with values that are somehow malformed.

However, since your method is called is_it_correct already, why not just return a boolean that answers the question that is the method name?

Call signature

Right now, is_it_correct takes one argument per valid choice. What if, at some point, you want to add another test to your program? You would have to create a method that takes an additional valid choice as argument. But then, you would run into trouble with the difficulty selection - it still only has two valid choices.

I recommend using an array for the valid choices for extensibility's sake.

Separation of concerns

Right now, the is_it_correct method is in charge of validating the correctness of the input as well as printing out an error message. I recommend moving the error message to the point in your code where other user interaction takes place already - namely close to the input calls.

With all of the above recommendations considered, is_it_correct and its usage could look like this:

def is_it_correct(choice, valid_choices):
 return choice in valid_choices
while True:
 test = input()
 test_choices = ["computer science", "history", "music"]
 if is_it_correct(test, test_choices):
 break
 else:
 print("Sorry, you didn't input valid settings. Available choices: " + ", ".join(test_choices))

Deduplication

You have two while True loops doing something very similar - prompting the user for one of a given set of choices and displaying an error message if he fails to enter a valid choice. Why not wrap that up in a method?

def require_input(prompt, choices):
 # generate a readable list of choices
 choices_string = "{} or {}".format(", ".join(choices[:-1]), choices[-1]).capitalize()
 # build the prompt message dynamically
 msg = "{} {}?\n".format(prompt, choices_string)
 while True:
 user_choice = input(msg)
 if is_it_correct(user_choice, choices)
 return user_choice
 print("Please input either " + choices_string + ".")
tests = ["computer science", "history", "music"]
test = require_input("What test do you want to take?", tests)
difficulty_levels = ["easy", "medium", "hard"]
difficulty = require_input("How difficult do you want the test to be?", difficulty_levels)
answered Sep 26, 2017 at 1:44
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.