I'm trying to create a recursive function that checks if a grade can be converted to a float, then checks to make sure the grade is between 0 and 100. My logic as to why this would work is:
Checks to see if the grade can be converted to a float.
If it can't be converted into a float, the user receives an error message, has to input a new grade, and gradeChecker checks again.
If it can be converted into a float, gradeChecker checks to see if it's between 0 and 100
If the grade between 0 and 100, the grade is then appended to the Assignments dictionary.
If the grade isn't between 0 and 100, the user gives a new grade, which is passed back in to the function, so repeat starting at step 1.
Can you tell me how this code doesn't follow that logic?
def gradeChecker(grade):
while True:
try:
grade = float(grade)
while (grade < 0) or (grade > 100):
print("Sorry, your grade must be between 0 and 100.")
grade = input("What grade did you receive on: %s? " % assignment)
gradeChecker(grade)
except:
print("Sorry, that's an invalid input. Please only use numbers and decimal points!")
grade = input("What grade did you receive on: %s? " % assignment)
else:
break
Assignments[assignment].append(grade)
Edit: Indentations fixed!
For reference, here is the entirety of the code I am using to pass grade into gradeChecker.
import collections #We import collections so we can use an ordered dictionary
Assignments = collections.OrderedDict() #We create an ordered dictionary called 'Assignments'
#We have to add each assignment to our dictionary individually because it's an ordered dictionary
#You can't convert a regular dictionary, which is unordered, to an ordered dictionary
#If you used a regular dictionary, when looping through the assignments they would be displayed at random
Assignments['Exam 1'] = [0.2] #We add the assignment and the weight to the dictionary
Assignments['Exam 2'] = [0.2] #We add the assignment and the weight to the dictionary
Assignments['Exam 3'] = [0.2] #We add the assignment and the weight to the dictionary
Assignments['Homework'] = [0.2] #We add the assignment and the weight to the dictionary
Assignments['LQR'] = [0.1] #We add the assignment and the weight to the dictionary
Assignments['Final'] = [0.1] #We add the assignment and the weight to the dictionary
#We have to define our grade checker before it is called so that it can be used to verify users inputs
def gradeChecker(grade): #Used to verify that a users grades are in-between 0 and 100
while True:
try:
grade = float(grade)
while (grade < 0) or (grade > 100):
print("Sorry, your grade must be between 0 and 100.")
grade = input("What grade did you receive on: %s? " % assignment)
gradeChecker(grade)
except:
print("Sorry, that's an invalid input. Please only use numbers and decimal points!")
grade = input("What grade did you receive on: %s? " % assignment)
else:
break
Assignments[assignment].append(grade) #We append the grade to the assignment to be used with it's weight for the final grade calculation
#INPUT
for assignment in Assignments.keys(): #We loop through every assignment in our Assignments dictionary
grade = input("What grade did you receive on: %s? " % assignment) #We ask the user to enter their grade
gradeChecker(grade) #We check to see if their grade is valid by passing their input through the gradeChecker function
Using both recursion and loop here is redundant. Moreover, loops should be preferred to recursion in 'normal' languages like Python (i.e., not Lisp) unless you're dealing with an inherently recursive data structure like a tree.
Given that you never stated why you need to use recursion in the first place, I suggest to use something like this:
def input_grade(assignment):
while True:
try:
grade = input("What grade did you receive on: %s? " % assignment)
grade = float(grade)
if grade < 0 or grade > 1000:
raise ValueError
return grade
except:
print("Sorry, that's an invalid input. Please only use numbers and decimal points!")
for assignment in Assignments:
Assignments[assignment].append(input_grade(assignment))
Note 1. I didn't test the code above, but it should give you the general idea of how to structure this function.
Note 2. You should avoid modifying Assignments in the function, that's an unwanted side effect. Better offload this to the main code.
Note 3. Technically, the try..except in my code is an example of exception-based logic, which isn't a great thing (however, this is way better than using recursion here).
def gradeChecker(grade):
try:
grade = float(grade)
while (grade < 0) or (grade > 100):
print("Sorry, your grade must be between 0 and 100.")
grade = input("What grade did you receive on: %s? " % assignment)
gradeChecker(grade)
except:
print("Sorry, that's an invalid input. Please only use numbers and decimal points!")
grade = input("What grade did you receive on: %s? " % assignment)
else:
Assignments[assignment].append(grade)
the thing with your code is that it's redundant; the while statement is there to do what you already have the recursive calls doing. imo, the while statement is better since recursion often uses up more memory but thats just an opinion.
Related
This question already has answers here:
Asking the user for input until they give a valid response
(22 answers)
How do I check if a string represents a number (float or int)?
(39 answers)
Closed 8 months ago.
I can't figure out how to handle any exceptions for non-int or float inputs on the program below. Could you guys please point me in the right direction?
def GradeAverager(): #Creating the function of the grade averager
#User initiation input
response = input("\n\nWould you like to average your grades? Press Y for "
"Yes or N to exit: ")
#Defined controlled repsonse variables
y="Y"
n="N"
if response in ["y","Y"]: #If statement based on response (allows for
#different variatios of the inputs)
# User input the # of grades to average
numOfGrades = float(input("\n\nEnter number of grades to be averaged: "))
if type(numOfGrades) is not float:
#Handles non-int exception (NOT WORKING)
raise TypeError("Only Numbers please!")
#Defining the variables for the while statement
x=0
grades = 0
rounded_average = 0
while x < numOfGrades: # While loop to keep asking the user for grades
# based on "numOfGrades"
grades += float(input("\n Enter Grade: ")) # User input is taken
# and added to grades
if not type(grades) is not float:
#Handles non-int exception (NOT WORKING)
raise TypeError("Only Numbers please!")
x += 1 # keeps the loop repeating until it is no longer true
average = grades/numOfGrades # Takes the total of grades and divides it
# by numOfGrades to calculate average
rounded_average = round(average, 1) #Rounds the total to two one decimal
print("\n\nYour Grade Average is: " + str(rounded_average))
#If statements based on result scores
if average > 70:
print("\n You are passing but should study harder :|\n\n")
elif average > 80:
print("\n Good Job! you're getting there! :)\n\n")
elif average > 90:
print("\n Awesome Job! You are Acing this! XD\n\n")
else:
print("\n You need to go back and study! :(\n\n")
elif response in ["n","N"]: #If user answers "no", ends the program
print("\n\nGood Luck!\n\n")
else:
print("\n\nIncorrect Entry\n\n")
GradeAverager()
print("\n\n*****Welcome to the Grade Averager******") #Prints the title
GradeAverager() #Calls the function
You just have an extra "not" in the line:
if not type(grades) is not float:
Change it to:
if not (type(grades) is float):
But in general it's better to do it like this:
if isinstance(grades, float):
but if you dig deeper, you'll realize that grades will always be of type float, only if the value from the input is correct. You need to check this. Review this and decide how best to check if the input value is a valid representation of a number.
UPD:
And as rightly noted in the comments, almost the same with the numOfGrades variable
I wanted to know if there was any way to end a conditional early. For example, when I run the code and enter all values in between 0-100 the program does what it's supposed to. However, let's say I put a negative number as input #3. The program keeps on going until the very end, then I get "Invalid input. Enter a number between 0-100". I'm wondering if there is any way I can get that message as soon as I enter a number that's not in between 0-100. I'm a complete beginner, so I really don't know what I'm doing.
def e5():
stdnt1 = float(input("Enter the first grade: "))
stdnt2 = float(input("Enter the second grade: "))
stdnt3 = float(input("Enter the third grade: "))
stdnt4 = float(input("Enter the fourth grade: "))
stdnt5 = float(input("Enter the fifth grade: "))
if(0 <= (stdnt1 and stdnt2 and stdnt3 and stdnt4 and stdnt5) <= 100):
avrg = (stdnt1 + stdnt2 + stdnt3 + stdnt4 + stdnt5) / 5
print("The groups average is", avrg)
grades = [stdnt1, stdnt2, stdnt3, stdnt4, stdnt5]
grades.sort()
print("The lowest grade is", grades[0])
else:
print("Invalid input. Enter number between 0-100")
I would recommend writing a function that takes the input and processes it.
def get_input(prompt):
response = float(input(prompt))
if 0 <= response <= 100:
return response
raise ValueError("Invalid input - enter number between 0-100")
This also has the advantage of simplying the first 5 lines of your function.
def e5():
stdnt1 = get_input("Enter the first grade")
# ...
You could also change the function to continue to ask the user using a while loop for valid input.
Hopefully this is enough to get you started.
Yes. Perform some preliminary checks as soon as you get the input. Example:
stdnt3 = float(input("Enter the third grade: "))
if not (0 <= stdnt3 and stdnt3 <= 100):
raise SystemExit("Error: value is not between 0 and 100.")
stdnt4 = float(input("En...
Edit
Note that your if-condition doesn't work as you expect. This:
if(0 <= (stdnt1 and stdnt2 and stdnt3 and stdnt4 and stdnt5) <= 100):
Will be (logically) turned into:
# Step 1
booleanValue = stdnt1 and stdnt2 and stdnt3 and stdn4 and stdnt5 # a True or False
# Step 2
if 0 <= (booleanValue) <= 100
# Step 3
if (0 <= booleanValue) <= 100
# Step 4
if TrueOrFalse <= 100
TrueOrFalse will be True (casting usually to the number 1) or False (casting usually to the number 0). That means that the if-condition will always evaluate to True and your else will never get called. Instead, check each value individually, either with multiple if statements, or in a single if statement:
if (0 <= stdnt1 and stndt1 <= 100) and (0 <= stndt2 and stndt2 <= 100) and ...
Divide up your problems. You're trying to achieve two separate things here:
Validate your inputs
Calculate an average
Write separate functions for each of these... well.. functions!
def validate_grade(grade):
if grade < 0 or grade > 100:
raise InvalidGrade() # This is a custom exception, I'll explain momentarily
return grade
So this function will check if a given number is between 0 and 100 inclusive, if not it will raise an exception. In this case it's a custom exception, so that we can catch it only if this particular case occurs. In all other circumstances, normal Python exceptions will be raised.
Let's define that exception.
class InvalidGrade(Exception):
pass
It really is just a standard exception with a different name! Easy but very helpful, here's how:
try:
stdnt1 = validate_grade(float(input("Enter the first grade: ")))
stdnt2 = validate_grade(float(input("Enter the second grade: ")))
stdnt3 = validate_grade(float(input("Enter the third grade: ")))
stdnt4 = validate_grade(float(input("Enter the fourth grade: ")))
stdnt5 = validate_grade(float(input("Enter the fifth grade: ")))
except InvalidGrade:
print("Invalid input. Enter number between 0-100")
else:
calculate_grades(stdnt1, stdnt2, stdnt3, stdnt4, stdnt5)
Great! Now it will gather input, raise an exception if any one of those inputs is invalid, otherwise it will execute the yet-to-be-defined calculate_grades function. But before we do that, we have some very repetitive code to clean up.
Lets ask ourselves what we're really repeating with these 5 grades. The only difference between each line is "first", "second", "third", etc.
Aha! We could create a list of grade names, and then python can loop over that list to build a list of grade values.
grade_names = ["first", "second", "third", "fourth", "fifth"]
try:
grade_values = [validate_grade(float(input("Enter the %s grade: " % name)))
for name in grade_names]
except InvalidGrade:
print("Invalid input. Enter number between 0-100")
else:
calculate_grades(*grade_values)
First we simply define a list of grade names by creating a list of strings.
Then inside the try block we use something called a list comprehension. It is simply a statement that gets evaluated for each item in a list, in this case that statement is the function validate_grade which happens to take the results of input then float as its parameters, and returns a value which is what will be saved in our grade values list.
Then, instead of passing each item one by one to calculate_grades, the * tells python to expand the list's elements as parameters for the function. Now if you were to say, add or remove a grade, you only have to change your code in one place.
Now for the final piece, lets define calculate_grades
def calculate_grades(*args):
avrg = sum(args) / len(args)
print("The groups average is", avrg)
print("The lowest grade is", min(args))
The whole solution together
GRADE_NAMES = ["first", "second", "third", "fourth", "fifth"]
class InvalidGrade(Exception):
pass
def validate_grade(grade):
if grade < 0 or grade > 100:
raise InvalidGrade()
return grade
def calculate_grades(*args):
print("The groups average is", sum(args) / len(args))
print("The lowest grade is", min(args))
try:
grade_values = [validate_grade(float(input("Enter the %s grade: " % name)))
for name in GRADE_NAMES]
except InvalidGrade:
print("Invalid input. Enter number between 0-100")
else:
calculate_grades(*grade_values)
I am learning Python this semester and this is my homework.
Can anyone tell me why my code is wrong?
QUESTION:
You want to know your grade in Computer Science, so write a program that continuously takes grades between 0 and 100 to standard input until you input "stop", at which point it should print your average to standard output.
MY CODE:
total=0
count=0
while True:
grade=input("Enter Your Grades between 0 and 100 [put 'stop' when done]:")
if grade<0 or grade>100:
print("Invalid Input")
continue
elif grade=="stop":
break
else:
count+=1
total+=grade
print "Your Average Grade is:"+format(total/count,'.2f')
When I run the code, the Python keeps giving me this messages:
Change input to raw_input
grade = raw_input("Enter Your Grades between 0 and 100 [put 'stop' when done]:")
You are using Python 2.7, so use raw_input instead of input. The latter evaluates the input, so 5 + 2 will return 7 instead of the string '5 + 2'. Entering stop tries to evaluate stop as a variable, which doesn't exist.
Another note, total and count are both integers, so total/count performs integer division in Python 2 (Python 3 gives a float result). If you want a floating point average, use float(total)/count. One of the variables must be float to get a float answer.
You'll also find that grade is a string, so test for 'stop' first, then convert it to an int to test the grade grade = int(grade). You might want to think about handling errors. What if the user types 10a?
You can evaluate first the string stop, try capture the input with raw_input:
total = 0
count = 0
while True:
grade = raw_input("Enter Your Grades between 0 and 100 [put 'stop' when done]:")
if grade == "stop":
break
if grade.isdigit():
grade = int(grade)
if grade < 0 or grade > 100:
print("Invalid Input")
continue
else:
count += 1
total += grade
if count == 0:
print "Empty values"
else:
print "Your Average Grade is: %.2f" % (float(total)/count)
I added different conditions for correct execution, check the lines, for example if grade.isdigit(): for verify that the input value is a numeric value, when this evaluation we can work normally with any math calculation.
count == 0: for the error division by zero if the user write stop in first iteration.
In the last line you can use two different ways to print the values:
print "Your Average Grade is: %.2f" % (float(total)/count)
or
print "Your Average Grade is: {:.2f}".format(float(total)/count)
You're running this program in Python 2 where input evaluates the user input. So if you enter "stop", Python tries to find the variable stop which doesn't exist and raises the NameError.
There are more problems and you need to restructure the code. The first thing you should do is to change input to raw_input which just returns the user input as a string. Then you need to check if the user entered "stop" and break, otherwise convert the input string to an int and then increment the count and total.
total = 0
count = 0
while True:
grade = raw_input("Enter Your Grades between 0 and 100 [put 'stop' when done]:")
if grade == "stop":
break
# Skip if the string can't be converted to an int.
if not grade.isdigit():
print("Invalid Input")
continue
# Now convert the grade to an int.
grade = int(grade)
if grade < 0 or grade > 100:
print("Invalid Input")
continue
else:
count += 1
total += grade
# Convert total to a float for true division.
print "Your Average Grade is: {:.2f}".format(float(total)/count)
trying to get a program to enter a students name and score, test it to make sure score is a vaule >=0 and <=100 and save results to a file and loop back
gradeFile = open("grade.dat","a")
Score = "0"
while Score>=0:
Name = raw_input("What is the students's name?: ")
Score = float(raw_input("What is the students's score?: "))
while Score <0 or Score >100 :
print("ERROR: the grade cannot be less than 0 or more than 100")
Score = float(raw_input("What is the students's score?: "))
gradeFile.write(Name+"\n")
gradeFile.write(Score+"\n")
gradeFile.close()
print("Data saved to grade.dat")
You need to have a way to exit the loop. For your outer loop, you automatically go in. Then you loop again until you get a valid score, via your inner loop, and you repeat. In your current configuration, there's no way to exit the loop.
Additionally, score should be a number, but you enter it as a string in Score = "0". When outputting, you're going to want to write str(Score) so that you can concatenate it with "\n".
I suggest that your outer loop have something like while Score >= 0 and userWantsToContinue. You can handle userWantsToContinue in whatever way you see fit.
Your datatpe doesn't match
Score = "0" # So, score is a string
while Score >= 0: # Oh, thenm it's a integer?
Im really stumped. Im writing a program for my teacher (Im using Python 3 btw), so that he can give this code to students to calculate their grade instead of waiting for their report card. I'm only a beginner so try and keep the answer simple please :D
Okay here is the problem. I have all of the inputs needed for the code. the inputs work like this. A = 5 B = 4 C = 3 D = 2 E = 1. If you got straight A's you'd get 50 points, and so on, but if it results in say, 35 points all the grade calculators will crash. Because if its >30 its a B, but if its >20 its a C, But >20 and >30 print at the same time. Because they both execute if the result is greater than 30. And i dont know how to make it so that it will print say, "B" if it is 31 to 40.
This is the code
a = eval(input())
b = eval(input())
c = eval(input())
d = eval(input())
e = eval(input())
f = eval(input())
g = eval(input())
h = eval(input())
i = eval(input())
j = eval(input())
average = a + b + c + d + e + f + g + h + i + j
print(average)
if average >41:
print(" Grade A ")
if average >31:
print(" Grade B")
if average >21:
print(" Grade C")
if average >11 :
print(" Grade D")
if average >0
print(" Grade E")
Any Help Would Be Greatly Appreciated! Thanks.
The best way to do what you want is to define a group of data. if/elif blocks work, but are ungainly, and require a lot of extra typing:
import sys
mark_boundaries = [("A", 41), ("B", 31), ("C", 21), ("D", 11), ("C", 0)]
try:
marks = []
for i in range(10):
marks.append(int(input()))
except ValueError:
print("You entered an invalid mark, it must be a number.")
sys.exit(1)
average = sum(marks) #I'd just like to note the misleading variable name here.
#average = sum(marks)/len(marks) #This would be the actual average mark.
print(average)
for mark, boundary in mark_boundaries:
if average >= boundary:
print("Grade "+mark)
break #We only want to print out the best grade they got.
Here we use a list of tuples to define our boundaries. We check from highest to lowest, breaking out if we match (so it doesn't 'fall through' to the lower scores).
Likewise, you can see that I have used a loop to gather the data in for the marks. A good sign that you are doing something in an inefficient way while programming is that you have copy and pasted (or typed out again and again) a bit of code. This generally means you need to put it in a loop, or make it a function. I also used int(input()) rather than eval(input()), which is a safer option, as it doesn't allow execution of anything the user wants. It also allows us to nicely catch the ValueError exception if the user types in something which isn't a number.
Note that an enterprising individual might look at a list of pair tuples and think a dict would be a good replacement. While true in most cases, in this case, we need to order to be right - in a dict the order is arbitrary, and might lead to us checking lower scores first, giving them a lower mark than they deserve.
Just as a note, it is entirely possible to do
if 31 < average < 41: #Equivalent to `if 31 < average and average < 41:`
print("Grade B")
In python. That said, for this usage, this would mean a lot more typing than using a list and loop or if/elif.
Basically, this is what you want:
if average >41:
print(" Grade A ")
elif average >31:
print(" Grade B")
elif average >21:
print(" Grade C")
elif average >11 :
print(" Grade D")
elif average >0
print(" Grade E")
else
print("You broke the system")
elif is short for else if, so it executes ONLY if the previous if/elif block was not executed.