Grade calculator range and ValueError - Python - python

I'm new to python and have been trying to create a simple grade calculator which tells the user what grade they've achieved based on their final score they've inputted.
def grades():
try:
score = int(input("Please enter your score between 0 and 100:"))
if score >= 90:
print("Grade:A")
elif score >= 80 :
print("Grade:B")
elif score >= 70:
print("Grade:C")
elif score >= 60:
print("Grade:D")
elif score >= 50:
print("Grade:E")
elif score < 50:
print("Grade:F")
except score not in range (0,101) or ValueError:
int(input("Incorrect value. Please enter your score between 0 and 100:"))
However when I try to run the program, it disregards the range and value error and gives it a grade anyway. Is there any way to rectify this, and if possible how could I make the program more efficient. As I said, I'm new to python, so any feedback would be useful.

Just for fun, let's make it a Match Case statement:
Since you only accept integers, we can take and assign score to input with :=, then check if it's valid with str.isnumeric. If that's true then we'll make score an integer := and check if it's between 0 and 100.
We'll change the input statement if they don't put valid input the first time around.
def grades():
text = "Please enter your score between 0 and 100: "
while True:
if ((score := input(text)).isnumeric() and
(score := int(score)) in range(0, 101)):
break
else:
text = "Incorrect value. Please enter your score between 0 and 100: "
match score:
case x if x >= 90 : grade = 'A'
case x if x >= 80 : grade = 'B'
case x if x >= 70 : grade = 'C'
case x if x >= 60 : grade = 'D'
case x if x >= 50 : grade = 'E'
case _ : grade = 'F'
print(f'Grade: {grade}')
Please note that this will only work in Python 3.10 or greater.

Just do this:
def grades():
try:
score = int(input("Please enter your score between 0 and 100:"))
if score > 100:
while True:
int(input("Incorrect value. Please enter your score between 0 and 100:"))
if score <= 100:
pass
else:
break
if score >= 90:
print("Grade:A")
elif score >= 80 :
print("Grade:B")
elif score >= 70:
print("Grade:C")
elif score >= 60:
print("Grade:D")
elif score >= 50:
print("Grade:E")
elif score < 50:
print("Grade:F")
except:
print("Oops. sommthing went wrong")
grades();

I made some corrections to your code. I added some comments to help explain what is going on. Let me know if this solution works for you:
def grades():
while True:
# Start a loop to ask for user input:
score = int(input("Please enter your score between 0 and 100:"))
# If not in range 1, 100, print error message
if score in range(0, 101):
break
print('Incorrect value. Please enter your score between 0 and 100:')
# calculate grade:
if score >= 90:
print("Grade:A")
elif score >= 80:
print("Grade:B")
elif score >= 70:
print("Grade:C")
elif score >= 60:
print("Grade:D")
elif score >= 50:
print("Grade:E")
elif score < 50:
print("Grade:F")
if __name__ == '__main__':
grades()

Simply assert that the input is in the determined range before checking through score ranges. Really, there is no need for a try/except statement.
def grades():
while True:
score = int(input(...))
if 0 <= score <= 100:
break
# Invalid score
# Check score ranges
...

I have made changes to your code, please test to ensure it performs to expectations.
I have added a while True loop, which attempts to validate the score to be between 0 - 100. If a non-integer value is entered it will hit the ValueError exception. This loop will only exit when a number within the range is entered.
The if statements use interval comparators X <= score < Y. You can read more about interval comparators here.
The if statement was also removed out of the try - except to make debugging easier. The idea is to have the least code possible in try - except so that when an exception triggers, it would be caused by the intended code.
Lastly, you don't want to ask for the user input inside the exception as the user might enter something which may cause another exception which will go uncaught.
def grades():
while True:
# Perform basic input validation.
try:
# Gets the user input.
score = int(input("Please enter your score between 0 and 100: "))
# Checks if the number entered is within 0 - 100. Note that range is non-inclusive for the stop. If it is within 0 - 100 break out of the while loop.
if 0 <= score <= 100:
break
# If a non-integer is entered an exception will be thrown.
except ValueError:
print("Input entered is not a valid number")
# Checking of scores using interval comparison
if score >= 90:
print("Grade:A")
elif 80 <= score < 90:
print("Grade:B")
elif 70 <= score < 80:
print("Grade:C")
elif 60 <= score < 70:
print("Grade:D")
elif 50 <= score < 60:
print("Grade:E")
else:
print("Grade:F")

Related

Ask a user for 10 integers one at a time and store in list- python

score = int(input("Please enter a bowling score between 0 and 300: "))
while score >= 1 and score <= 300:
scores.append(score)
score = int(input("Please enter a bowling score between 0 and 300: "))
print(scores)
I want the user to enter 10 integers one at a time in a loop and store all ten in a list called scores.
You could do something like this, if you do not need the number entered to be restricted within an interval:
scores = []
for i in range(10):
scores.append(int(input())
This will repeatedly wait for a user input, and store each value in the scores list.
If you want the number to be between 1 and 300, simply place the code you already have in a for loop, or create a counter. You could end up with something like this:
scores = []
for i in range(10):
score = 0
while score >= 1 and score <= 300:
score = int(input("Please enter a bowling score between 0 and 300: "))
scores.append(score)
print(scores)
If you're okay assuming that all of the input will be valid, you can simply do:
scores = [int(input("Please enter a bowling score between 0 and 300: ")) for _ in range(10)]
This will raise a ValueError if the input isn't convertable to an int, though, and it also won't check for it being in the range. If you want to re-prompt them on invalid inputs until you have 10 valid inputs, you could make "get a valid score" its own function and then build the list with 10 calls to that:
def get_score() -> int:
while True:
try:
score = int(input("Please enter a bowling score between 0 and 300: "))
if not (0 <= score <= 300):
raise ValueError(f"{score} isn't between 0 and 300")
return score
except ValueError as e:
print(f"Error: {e}. Please try again.")
scores = [get_score() for _ in range(10)]
If you want for the user to input in different lines then this should work:
inputList = []
for i in range(10):
inputList.append(input("Enter: "))
But if you want the user to input all values in same line then use:
inputList = map(int, input("Enter: ").split())
Let's do a different approach than "try this" as it looks like you're a beginner.
To ask a user for an input you can use the input() function. It'll give you a string. To convert a string to a number you can utilize int(), float() or other functions depending on the properties the number should have (decimal numbers, precision, etc).
To repeat a certain action you need to use a loop. You know while as seen in your code. The loop keyword can be nested i.e. you can have a loop within a loop and you can arrange it so that it's checking for the amount of numbers outside of the number limit condition e.g.:
mylist = []
while len(mylist) < 10:
num = int(input("some text"))
while <your number condition>:
mylist.append(num)
...
...
or you can utilize for loop that will execute the block of code only N-times e.g. with range(10):
mylist = []
for _ in range(10):
num = int(input("some text"))
while <your number condition>:
mylist.append(num)
...
...
With a while loop you need to watch out for cases when it might just infinitely loop because the condition is always true - like in your case:
scores = []
score = < a number between 1 and 300, for example 1>
while score >= 1 and score <= 300: # 1 >= 1 and 1 <= 300 <=> True and True
scores.append(score)
score = int(input("Please enter a bowling score between 0 and 300: "))
print(scores)
which will exit in case you enter a number out of the interval but does not guarantee the N-times (10-times) you want. For that to happen you might want to adjust the loop a bit with break to stop the execution after 10 values are present:
scores = []
score = < a number between 1 and 300, for example 1>
while score >= 1 and score <= 300: # 1 >= 1 and 1 <= 300 <=> True and True
scores.append(score)
score = int(input("Please enter a bowling score between 0 and 300: "))
if len(scores) >= 10:
break # stop the while loop and continue to "print(scores)"
print(scores)
However that doesn't handle cases such as inputting 0 or 1000 let's say as once you choose the number out of the interval, it'll stop the while loop even if the amount of scores is less than 10.
And then there's the obvious ValueError when you simply press Enter / Return without entering a number or supply a non-numeric value such as two which is still a number, but will only crash instead converting to 2 with int().
For the first you'd need to encapsulate the number check in other loop or refactor it into something like this:
mylist = []
while len(mylist) < 10:
num = int(input("some text"))
if num >= 1 and num <= 300:
mylist.append(num)
which handles even wrong numeric input e.g. 1000 and will ask for another number.
To handle non-numeric input there are at least two ways - you either let it fail or you check the value first:
With fail first you pass the invalid value to int() automatically and Python interpreter will generate and raise an Exception.
mylist = []
while len(mylist) < 10:
try:
num = int(input("some text"))
except ValueError as error:
# do something with the error e.g. print(error)
# or let it silently skip to the next attempt with "continue"
continue
if num >= 1 and num <= 300:
mylist.append(num)
With value validating you can use isnumeric() method which is present on any string instance (which for your case is the return value of input() function):
mylist = []
while len(mylist) < 10:
num = input("some text")
if not num.isnumeric():
continue
if num >= 1 and num <= 300:
mylist.append(num)
And to make it more compact, you can chain the comparison, though with one unnecessary int() call when the value is correct assuming most of the values are incorrect. In that case num.isnumeric() evaluates to False first and prevents all int() calls while if the input is numberic you end up calling isnumeric() and 2x int():
mylist = []
while len(mylist) < 10:
num = input("some text")
if num.isnumeric() and 1 <= int(num) <= 300:
mylist.append(int(num))
or the other way around, assuming most of the values are correct you can go for the edge-case of incorrect value with try which would be slower afaik but should be faster than always asking whether a string isnumeric().
mylist = []
while len(mylist) < 10:
try:
num = int(input("some text"))
except ValueError:
continue
if 1 <= num <= 300:
mylist.append(num)
Each of the approaches has its own trade off. You can strive for readability, performance, compactness or any other trait and depending on the trait there will be a way to measure it e.g. for performance you might want to use time.time and for readability a linter such as pylint.
A minor extra, in case you are creating a CLI tool, you might want to handle Ctrl + C (interrupt/kill program, will raise KeyboardInterrupt) and Ctrl + D (end input, will raise EOFError). Both can be handled with try/except.
First, you have to define the list 'scores'.
while score >= 1 and score <= 300: means that if the input value does not between 0 and 300, the loop will be over. Therefore, you may not be able to complete the list of 10 integers. You can check this condition by using if instead of while.
The while loop need to check if the scores list has 10 elements or not.
scores = []
while len(scores) < 10:
score = int(input("Please enter a bowling score between 0 and 300:"))
if (1 <= score <= 300):
scores.append(score)
else:
print("Score must be between 0 and 300")
print(scores)

Using “and” operator to compare two values

Very new to python and trying to figure out how to use the and operator to check if a number is between 50 and 100. Tried using and, && and || , but just getting invalid syntax python parser-16 error. If I take the and or alternative out of the code, then it partly works and dosn't give me a error message, though it dosn't check if the value is below 100, so presumly it must the and part that I'm doing wrong?
x = int(input("Enter a number between 0 and 100"))
if x < 50:
print("That is below 50!")
elif x > 50 and < 100:
print("That is above 50!")
else:
print("That number is too high!")
close!
x = int(input("Enter a number between 0 and 100"))
if x < 50:
print("That is below 50!")
elif x > 50 and x < 100:
print("That is above 50!")
else:
print("That number is too high!")
if x > 50 and x < 100 you have to reference it each time you check if its true
Alternative solution:
x = int(input("Enter a number between 0 and 100: "))# for a better look
if x < 50:
print("That is below 50!")
elif 100 >= x >= 50:# the numbers 50 and 100 shall be inclusive in one of the three params
print("That is between 50 and 100!")
else:
print("That number is too high!")
To simplify it more, you can write as below.
x = int(input("Enter a number between 0 and 100"))
if x < 50:
print("That is below 50!")
elif 50 < x < 100:
print("That is above 50!")
else:
print("That number is too high!")
If x<50:
print('Below 50')
elif x>50 and x<100:
print('Between 50 and 100');
else:
print('Above 100');
Try this

Function returns None after wrong input

I need a function that excepts wrong input and asks to input once more. But after wrong input it returns None instead of new input. What is wrong with my code and how can I solve this?
def start():
def inputNumber(answer):
try:
number = int(input(answer))
if number <= 100 and number >= 0:
print('%%%',number,'%%%')
return number
else:
inputNumber('Number is wrong, please input number from 0 to 100: ')
except (ValueError):
inputNumber('It is not a number, please input number from 0 to 100: ')
def checkInput(number2):
print('$$$',number2,'$$$')
if number < 50:
return number2
else:
return checkInput(inputNumber('Input number from 0 to 100: '))
number = 0
print('###',checkInput(inputNumber('Input number from 0 to 100: ')),'###')
start()
start()
This is the result:
Input number from 0 to 100: 777
Number is wrong, please input number from 0 to 100: sadf
It is not a number, please input number from 0 to 100: 17
%%% 17 %%%
$$$ None $$$
TypeError: unorderable types: NoneType() < int()
You are calling inputNumber recursively but don't return the result of the recursive call. Better use loops instead of recursion:
def inputNumber(prompt):
while True:
try:
number = int(input(prompt))
if 0 <= number <= 100:
print('%%%',number,'%%%')
return number
prompt = 'Number is wrong, please input number from 0 to 100: '
except ValueError:
prompt = 'It is not a number, please input number from 0 to 100: '
Btw: you should also use loops in your other functions, and don't define nested functions.
run this code it will solve your problem. you just need to catch as extra error (NameError)
def start():
def inputNumber(answer):
try:
number = int(input(answer))
if number <= 100 and number >= 0:
print('%%%',number,'%%%')
return number
else:
inputNumber('Number is wrong, please input number from 0 to 100: ')
except (ValueError, NameError) as e:
inputNumber('It is not a number, please input number from 0 to 100: ')
def checkInput(number2):
print('$$$',number2,'$$$')
if number < 50:
return number2
else:
return checkInput(inputNumber('Input number from 0 to 100: '))
number = 0
print('###',checkInput(inputNumber('Input number from 0 to 100: ')),'###')
start()
start()
The problem is that once you fail a check you call inputNumber again, but don't do anything with the answer. You need to return it.
def start():
def inputNumber(answer):
try:
number = int(input(answer))
if number <= 100 and number >= 0:
print('%%%', number, '%%%')
return number
else:
return inputNumber('Number is wrong, please input number from 0 to 100: ')
except (ValueError):
return inputNumber('It is not a number, please input number from 0 to 100: ')
def checkInput(number2):
print('$$$', number2, '$$$')
if number < 50:
return number2
else:
return checkInput(inputNumber('Input number from 0 to 100: '))
number = 0
print('###', checkInput(inputNumber('Input number from 0 to 100: ')), '###')
start()
start()

variables not defined in if statements for change counting program

I'm making a change counter and I'm having trouble printing the percentage for a grade, whenever I run the program I can enter as many inputs as I want, however, when I type done, which is supposed to terminate the program and leave the user with the percentage and letter grade, it just ends the program. If I could get any advice it would be greatly appreciated.
here's my code:
grade=""
total=0
count=1
scores=''
while scores != 'done':
scores=input("Enter Homework score: ")
if scores.isdigit():
numeric=int(scores)
percentage=(numeric*10/count)
elif percentage >= 92 and percentage < 100:
letter = 'A'
elif percentage >= 87 and percentage < 92:
letter = 'B+'
elif percentage >= 80 and percentage < 87:
letter = 'B'
elif percentage >=77 and percentage < 80:
letter = 'C+'
elif percentage >=70 and percentage < 77:
letter = 'C'
elif percentage >= 67 and percentage < 70:
letter = 'D+'
elif percentage >= 60 and percentage < 67:
letter = 'D'
elif percentage < 60 and percentage >= 0:
letter= 'F'
elif (numeric) < 0:
print("Score must be between 0 and 10")
elif (numeric) > 10:
print("Score must be between 0 and 10")
elif (scores)== 'done':
print(percentage,"% and you got an, ",letter)
Your conditional logic is flawed. You are never assessing the grade (letter) if the score.isdigit():
while scores != 'done':
scores=input("Enter Homework score: ")
if scores.isdigit():
numeric=int(scores)
percentage=(numeric*10/count)
if percentage >= 92 and percentage < 100:
letter = 'A'
elif percentage >= 87 and percentage < 92:
letter = 'B+'
...
It is often cleaner to jump out of the loop if the initial condition is false, e.g.:
while scores != 'done':
scores=input("Enter Homework score: ")
if not scores.isdigit():
continue
numeric=int(scores)
percentage=(numeric*10/count)
if 92 <= percentage < 100:
letter = 'A'
elif 87 <= percentage < 92:
letter = 'B+'
...
Also in python your shouldn't be afraid of exceptions. A common idiom in python is EAFP (Easier to Ask for Forgiveness than Permission):
while scores != 'done':
scores=input("Enter Homework score: ")
try:
numeric = int(scores)
except ValueError:
continue
You might also want to think about better ways of doing the large grade if elif elif ... block. E.g. an alternative approach would be define a dictionary of the grades:
grades = {'A': (92, 100), 'B+': (87, 92)} # Etc..
score = 93
_, letter = max((low <= score < high, letter) for letter, (low, high) in grades.items())
print(letter) # 'A'
Your code should look similar to the one below. Although I still cannot assess the logic behind your program (because you did not explain that in your question, e.g. percentage=(numeric*10/count) does not seem quite right to me, etc.), but the code below solves your current problem (based on your current question).
grade=""
total=0
count=1
scores=''
percentage = 0
while scores != 'done':
scores=input("Enter Homework score: ")
if scores.isdigit():
numeric=int(scores)
if numeric < 0:
print("Score must be between 0 and 10")
elif numeric > 10:
print("Score must be between 0 and 10")
percentage=(numeric*10/count)
if percentage >= 92 and percentage < 100: # I would change this to if percentage >= 92 and percentage <= 100:
letter = 'A'
elif percentage >= 87 and percentage < 92:
letter = 'B+'
elif percentage >= 80 and percentage < 87:
letter = 'B'
elif percentage >=77 and percentage < 80:
letter = 'C+'
elif percentage >=70 and percentage < 77:
letter = 'C'
elif percentage >= 67 and percentage < 70:
letter = 'D+'
elif percentage >= 60 and percentage < 67:
letter = 'D'
elif percentage < 60 and percentage >= 0: #I would change this to else:
letter= 'F'
print(percentage,"% and you got an, ",letter)

While loop in python not working

pointsToAdd = 30
strengthPoints = 0
healthPoints = 0
wisdomPoints= 0
dexterityPoints = 0
while pointsToAdd > 0:
choice = int(input("Choice(1-4): "))
if choice == 1:
pointsToAdd = int(input("How many Strength points would you like to add: "))
if pointsToAdd < 31 and pointsToAdd > 0 and pointsToAdd - strengthPoints > 0:
strengthPoints += pointsToAdd
pointsToAdd -= strengthPoints
print("You now have",strengthPoints,"strength points")
elif pointsToAdd > 30:
print("You cannot add that many!")
elif pointsToAdd<1:
print("You cannot add less than one point!")
elif pointsToAdd - strengthPoints <= 0:
print("You only have",pointsToAdd,"points!")
else:
print("We are sorry, but an error has occurred")
I am trying to make it so that the user can enter points for any of the four categories, but has no more than 30 points to expend(I have not yet written the code for the health, wisdom or dexterity points). Why when i run the program does the loop only run again if you choose to add a number of points between 1-30? If the user enters the points they want to allocate towards strengthPoints using numbers not between 1-30, the loop will run the associated if statement, but will not run through the loop again, why is this the case?
you are using the same variable for two different purposes pointsToAdd. You have it as the total points to assign, and what was selected by the user to add to a stat. Once you stomp the total points to assign with the users choice, you then add it to the 0 strength and subtract it from your user entered value, setting it to zero. Using to separate variables like below will fix it.
totalPointsToAdd = 30
strengthPoints = 0
healthPoints = 0
wisdomPoints= 0
dexterityPoints = 0
while totalPointsToAdd > 0:
choice = int(input("Choice(1-4): "))
if choice == 1:
pointsToAdd = int(input("How many Strength points would you like to add: "))
if pointsToAdd < 31 and pointsToAdd > 0 and pointsToAdd - strengthPoints > 0:
strengthPoints += pointsToAdd
totalPointsToAdd -= pointsToAdd
print("You now have",strengthPoints,"strength points")
You do
pointsToAdd = 30
Then in the loop
pointsToAdd = int(input("How many Strength points would you like to add: "))
Then in the test
# Here pointsToAdd is not 30, but the value inputed by the user
strengthPoints += pointsToAdd
# Here strengthPoints == pointsToAdd == the value from the input
pointsToAdd -= strengthPoints
# Here pointsToAdd == 0
This results in pointsToAdd == 0 after than.
You need to use another variable for the input of your user.
As other pointed out you are overwriting the same variable pointsToAdd. I also consider that you can cut down your conditions to two:
pointsToAdd = 30
strengthPoints = 0
while pointsToAdd:
print ('You have', pointsToAdd, 'available points.')
choice = int(input("Choice(1-4): "))
if choice == 1:
toBeAdded = int(input("How many Strength points would you like to add: "))
if toBeAdded < 1: # Can't assign negative or null values
print("You cannot add less than one point!")
continue
if toBeAdded > pointsToAdd: # Don't have enough points to spend
print("You only have", pointsToAdd, "available points!")
continue
strengthPoints += toBeAdded
pointsToAdd -= toBeAdded
print("You now have", strengthPoints, "strength points")
In Python 2.x use: raw_input
In Python 3.x use: input
If you want compatibility between Python 2.x and 3.x, you can use:
try:
input = raw_input
except NameError:
pass

Categories