I'm currently practicing on how to raise custom exceptions with multiple user input. How do I get to this desired output?
Terminal:
Enter assignment mark (0-20): 25
Assignment mark must be between 0 and 20
Enter assignment mark (0-20): 2
Enter project mark (0-30): 50
Project mark must be between 0 and 30
Enter project mark (0-30):
Current output:
Enter assignment mark (0-20): 25
Assignment mark must be between 0 and 20
Enter assignment mark (0-20): 2
Enter project mark (0-30): 50
Project mark must be between 0 and 30
Enter assignment mark (0-20):
It keeps looping back to the first question.
I appreciate anybody who can help and explain. Thanks!
Code:
class rangeError(Exception):
def __init__(self, message):
self.message = message
while True:
try:
assignment_mark = int(input("Enter assignment mark (0-20): "))
if assignment_mark > 20 or assignment_mark < 0:
raise rangeError("Assignment mark must be between 0 and 20")
project_mark = int(input("Enter project mark (0-30): "))
if project_mark > 30 or project_mark < 0:
raise rangeError("Project mark must be between 0 and 30")
final_exam_mark = int(input("Enter final exam mark (0-50): "))
if final_exam_mark > 50 or final_exam_mark < 0:
raise rangeError("Exam mark must be between 0 and 50")
total_mark = assignment_mark project_mark final_exam_mark
print(total_mark)
except ValueError as e:
print("Please enter integers")
except rangeError as e:
print(e)
except Exception as e:
print(e)
CodePudding user response:
Whenever an exception occurs you start with the try block again (due to while True
). You never terminate or check whether the values have already been defined. When you reach the total_mark output, you also start all over again. I would suggest you retrieve the values separately using a function, to avoid duplication. Note the return mark
, which exits the function and therefore the while True
as soon as a proper value has been provided:
class rangeError(Exception):
def __init__(self, message):
self.message = message
def get_mark(name, val_range):
lo, hi = val_range
while True:
try:
mark = int(input(f"Enter {name} mark ({lo}-{hi}): "))
if mark > val_range[1] or mark < val_range[0]:
raise rangeError(f"{name.capitalize()} mark must be between {lo} and {hi}")
return mark
except ValueError as e:
print("Please enter integers")
except rangeError as e:
print(e)
except Exception as e:
print(e)
assignment_mark = get_mark("assignment", [0, 20])
project_mark = get_mark("project", [0, 30])
final_exam_mark = get_mark("final exam", [0, 50])
total_mark = assignment_mark project_mark final_exam_mark
print(total_mark)
CodePudding user response:
When the error occurs in the try
block, Python will jump to the exception blocks and find the correct error to raise. When the error is handled, it loops to the top of the while-block. That is why your code is starting over.
There are a couple of ways to handle it. One is to have a while loop for each input. Another way is to set variables in your global scope that hold the values of assignment_mark
, project_mark
, and final_exam_mark
. You can then check if the value exists and skip to the correct chunk of code. Since all three of your checks are for a range, you can wrap the check as a function to shorten you code.
class RangeError(Exception):
def __init__(self, min_, max_):
self.min_ = min_
self.max_ = max_
def __str__(self):
return f'Input value must be between {self.min_} and {self.max_}.'
def range_check(x, min_, max_):
if min_ <= x <= max_:
return x
raise RangeError(min_, max_)
def get_input_within_range(input_msg, min_, max_):
mark = range_check(int(input(f"{input_msg} ({min_}-{max_}): ")), min_, max_)
return mark
assignment_mark = None
project_mark = None
final_exam_mark = None
total_mark = None
while True:
try:
if assignment_mark is None:
assignment_mark = get_input_within_range("Enter assignment mark", 0, 20)
if project_mark is None:
project_mark = get_input_within_range("Enter project mark", 0, 30)
if final_exam_mark is None:
final_exam_mark = get_input_within_range("Enter final exam mark", 0, 50)
if total_mark is None:
total_mark = assignment_mark project_mark final_exam_mark
print(f'Total mark is: {total_mark}')
else:
quit_ans = input("Type 'Q' to quit, anything else to restart: ")
if quit_ans.upper() == 'Q':
break
else:
assignment_mark = None
project_mark = None
final_exam_mark = None
total_mark = None
except ValueError as e:
print("Please enter integers")
except RangeError as e:
print(e)
except Exception as e:
print(e)