Python Input Validation with multiple variables...simplified? - python

First, I've searched this site, a lot, and found other posts about this topic, even the same assignment I'm working on, so the code is very similar... However, there are a few things slightly different. I'm taking this course, using "Starting out with Python, 4th edition," and my assignment is from chapter 5, "15. Test Average and Grade." I've got the code written for everything except input validation, which my instructor insists we use, though we are only supposed to use coding techniques the book has covered up to this point: no lists, tuples, dictionaries, lambda, etc... Which makes most of the examples I've found online (and on this site) for input validation useless, as I can't figure them out and couldn't use them if I wanted to. I've reached out to the instructor for help (online course), but haven't received any reply for weeks, so I'm here. The program is supposed to ask the user to input 5 test scores, find the average of the scores, assign a letter grade to each score, then display the scores w/ letter grade as well as the average. I thought it'd be easier to validate the input if I asked for the scores with a "for scores in range(1, 6)" loop, but then I don't know how to access each score input by the user to send to the determine_grade function and later to display in main (I didn't include any of that code below)... So I ended up making a variable for each score, but then I run into the problem of how to validate the input (make sure the score entered isn't less than 0 or greater than 100, or that the user has entered a number and not a letter) for each variable. I'd like to be able to write some exception handling into the code so that if the user has entered a letter instead of a number an exception isn't thrown, because my instructor has said "it's my job from now on to try to crash your program," though he hasn't gotten back to me on exactly how to implement this kind of input validation. Any help at all would be greatly appreciated, I've been struggling with this for days now, and it's seriously stressing me out.
EDIT: TypeError: input_validation() missing 4 required positional arguments: 'score2', 'score3', 'score4', and 'score5' is the error I'm getting, I know I'm doing something wrong, however, I don't know what... I feel like there is an easier way to handle input validation for multiple variables.. Since I'm still quite new at this, I've no idea whatsoever how to implement it though.
def get_scores():
score1 = input_validation(float(input('Enter the score for the first test: ')))
score2 = input_validation(float(input('Enter the score for the second test: ')))
score3 = input_validation(float(input('Enter the score for the third test: ')))
score4 = input_validation(float(input('Enter the score for the fourth test: ')))
score5 = input_validation(float(input('Enter the score for the fifth test: ')))
return score1, score2, score3, score4, score5
def input_validation(score1, score2, score3, score4, score5):
while (score1, score2, score3, score4, score5) < 0 or (score1, score2, score3, score4, score5) > 100:
print('Score cannot be less than 0 or greater than 100!')
(score1, score2, score3, score4, score5) = float(input('Please enter a correct test score: '))
return score1, score2, score3, score4, score5

Your immediate error is that you've defined input_validation() to take five parameters, but you're only passing it one parameter when you call it.
It's awkward to collect input in one function and validate the input in another function, because those functions would have to be very tightly coordinated to allow for reprompting on bad input.
It's also awkward to ask for several scores at once and then validate them all at once, because what do you do if some scores are valid and some aren't? You have to either ask for all the scores again, which wastes the user's time, or you need a way of reprompting only for the invalid scores, which is needless complexity.
It might be a better design to handle just one score at a time, with all the input and validation in one place:
def input_validation(prompt):
# keep looping until they enter a good score
while True:
# get the answer as a string
answer = input(prompt)
try:
# convert to float
score = float(answer)
# if in range, we're done! return the converted score number
if 0 <= score <= 100:
return score
# otherwise out of range, print an error message and keep looping
else:
print('Score cannot be less than 0 or greater than 100!')
# if the answer wasn't a number, print an error message and keep looping
except ValueError:
print ('That is not a test score.')
Then you can call it like this:
score1 = input_validation('Enter the score for the first test: ')
score2 = input_validation('Enter the score for the second test: ')
If you want to keep the scores in a list instead of having five separate variables:
scores = []
for i in range(5):
scores.append(input_validation('Enter the score for test number %d: ' % i+1))

Related

Problems with random "Lists"

I want to create a game where a person is drawn out randomly.
Can some1 check the code if everything is setup correctly.
I have tested the code numerous times and its ok in my eyes.
But when I send the code to a review, to an online class I only get 50% score.
import random
# 🚨 Don't change the code below πŸ‘‡
test_seed = int(input("Create a seed number: "))
random.seed(test_seed)
# Split string method
names_string = input("Give me everybody's names, separated by a comma. ")
names = names_string.split(", ")
# 🚨 Don't change the code above πŸ‘†
#Write your code below this line πŸ‘‡
print(names)
names_count = len(names)
random_name_number = random.randint(0, names_count)
print(f"{names[random_name_number]} is going to buy the meal today!")
The problem here is almost certainly with randint. Unlike most Python conventions, the parameters to randint are inclusive. That means, if you supply (0,10), you are going to get numbers from 0 to 10. In your case, if they supply 10 names, using index 10 is going to cause an exception.
You want random.randrange, not random.randint. randrange(0,10) will supply numbers from 0 to 9.

How do I add numbers I've iterated into a list to a string?

I've got a tiny project I'm working on: I'm trying to make a "grading" program that lets you enter the number of exams, the scores for each exam, and then prints the results.
What I'm looking to do:
Enter the number of tests:
use that number with the string "Exam #: " to number each test.
I've gotten as far as sticking the input from "Enter the number of tests:" into a list..(looks like [0,1,2,3,4.. etc] now I'm trying to combine each of those list numbers with the above string and nothing I'm trying is working.. suggestions?
This is what I came up with, and its output:
test1 = int(input('How many tests are there? '))
test2 = []
for number in range(test1):
test2.append(number)
for number2 in test2:
print('Exam #:' + str(number2))
(inputting "5" here)
Exam #:0
Exam #:1
Exam #:2
Exam #:3
Exam #:4
exactly what I needed!
Try something link this
num_exams = int(input('Enter the number of exams: '))
exam_scores = [int(input(f'Enter score for exam #{n+1}: ')) for n in range(num_exams)]
print(f'Average score: {sum(exam_scores) / num_exams:0.2f}')
Seems like you'd want to collect inputs for the number of tests and then all the test scores. Then to print the test scores you could do something like
for test in range(numTests):
print('Exam #' + (test+1) + ': ' + testScores[test])
The (test+1) is so that you could have the same variable manage the test number as well as the index in the test array. For example, it could print
Exam #1: 82
Exam #2: 93
Exam #3: 87
Not sure if this is needed for your program, but you can iterate through all your values in a list with a for loop. This allows you you to access each value and perform some set of commands on that value. So in this example, we will access each value and then print it. Print can take multiple arguments. It will print out each argument with a space in between.
for examNumber in myList:
print ('Exam', examNumber)

How to update a global variable based on number of user inputs?

I am trying to make a list of weights that are being brought to a trip to outer space. The way I have tried to show how many people are coming is this:
def flcr():
try:
Value1 = int(input())
except ValueError:
print("That was an incorrect format! Try again.")
flcr()
global x
x = Value1
Then the user has to input the weights one by one. This is what I tried:
def enter():
print("How much is each flight crew member bringing on the trip? Enter one entry at a time, this will be Earth weight.")
amount1()
def amount1():
try:
if x > 0:
equation1 = [float(input())]
x - 1
amount1()
else:
print(listFlcr)
except ValueError:
print("That was an incorrect format! Try again.")
enter()
When I input the weights though, I assume x just resets itself instead of subtracting itself by 1, so my input is infinite. I want to have a code that will allow me to enter the right amount of weights, so if I say there are 2 people coming, I can only input two weights.
If someone could help me out I would greatly appreciate it!
There are a number of issues with your current implementation.
You are using recursion to repeat getting inputs, which means you have a function (flcr, amount1) that calls itself until valid inputs are provided. While this could work for user inputs, it is usually unnecessary. There are better ways to ask for user input until they give a valid response, and as mentioned in the comments, use a loop instead.
The code x-1 does not update x. It actually does nothing because the result is not stored anywhere. If you are using an IDE or a linter, it could warn you that this is a "pointless statement". What you probably wanted was x = x - 1.
You are using globals to track how many weights need to be input and how many were input so far. While this could also work, it is again unnecessary. It would be simpler to just pass the number of flight crew members as a function argument.
Here's a solution that replaces the recursive calls with while loops and gets the number of people from one function, then passes the result of that to another function for getting the weights:
def get_num_people():
while True:
try:
return int(input("How many people are coming? "))
except ValueError:
print("That was an incorrect format! Try again.")
def get_weights(num_weights):
print("How much is each flight crew member bringing on the trip?")
all_weights = []
while len(all_weights) < num_weights:
try:
all_weights.append(int(input()))
except ValueError:
print("That was an incorrect format! Try again.")
print(all_weights)
return all_weights
num_people = get_num_people()
get_weights(num_people)
Here's the sample output:
$ python test.py
How many people are coming? 2
How much is each flight crew member bringing on the trip?
12
33
[12, 33]
$ python test.py
How many people are coming? 3
How much is each flight crew member bringing on the trip?
abc
That was an incorrect format! Try again.
89
def
That was an incorrect format! Try again.
100
4
[89, 100, 4]
I know that your question was about how to update the global variable based on user inputs, ... but I think you have a global x because you were using recursive calls. A cleaner solution would be to get rid of both recursion and the global variable.
You don't need global before the comparison of x in that function.
Generally for me, I find it easier to refer to things I want global as globals()[β€˜x’]. That way I know nothing weird will happen. If globals() refers to global namespace, represented similar to a dictionary, globals()[β€˜x’] will always point to the global variable x.
If it is intended to be global, declare it globally before everything else. Outside all the functions, x = None, or x = 0, or x = β€˜β€™.
try to replace :
Value1 = int(input())
with :
Value1 = int(str(input("")))

How to match input with elements in list/dictionary in Python3

I'm very new at coding, and I'm trying to create a shop list with items and prices on it.
That is, once typed in all the items, the function should calculate the sum and stop the moment you exceed the budget.
So I wrote something like:
def shoplist():
list={"apple":30, "orange":20, "milk":60......}
buy=str(input("What do you want to purchase?")
If buy in list:
While sum<=budget:
sum=sum+??
shoplist ()
I really don't know how to match the input of an item with the price in the list...
My first thought is to use 'if', but it's kinda impractical when you have more than 10 items on the list and random inputs.
I'm in desperate need of help....So any suggestions would be nice!! (or if you have a better solution and think me writing it this way is complete garbage... PLEASE let me know what those better solutions are😭😭😭
The code you post will not run in python. list is a builtin and should not be used for a variable name, and is doubly confusing since it refers to a dict object here. input() already returns a str so the cast has no effect. if and while should be lowercase, and there is no indentation, so we have no way of knowing the limits of those statements.
There are so many things wrong, take a look at this:
def shoplist(budget):
prices = {"apple":30, "orange":20, "milk":60}
# Initialise sum
sum = 0
while sum <= budget:
buy = input("What do you want to purchase?")
# Break out of the loop if the user hts <RETURN>
if not buy: break
if buy in prices:
sum += prices[buy] # This gets the price
else:
print("Invalid item", buy)
shoplist(142)
So what have I changed? The budget has to come from somewhere, so I pass it in as a parameter (142, I made that up). I initialise the sum to zero, and I moved the while loop to the outside.
Notice as well lots of whitespace - it makes the code easier to read and has no effect on performance.
Lots of improvements to make. The user should be shown a list of possible items and prices and also how much budget there is left for each purchase. Note as well that it is possible to go over budget since we might only have 30 in the budget but we can still buy milk (which is 60) - we need another check (if statement) in there!
I'll leave the improvements to you. Have fun!
Take a look at this as an example:
# this is a dictionary not a list
# be careful not using python reserved names as variable names
groceries = {
"apple":30,
"orange":20,
"milk":60
}
expenses = 0
budget = 100
cart = []
# while statements, as well as if statements are in lower letter
while expenses < budget:
# input always returns str, no need to cast
user_input = input("What do you want to purchase?")
if user_input not in groceries.keys():
print(f'{user_input} is not available!')
continue
if groceries[user_input] > budget - expenses:
print('You do not have enough budget to buy this')
user_input = input("Are you done shopping?Type 'y' if you are.")
if user_input == 'y':
break
continue
cart.append(user_input)
# this is how you add a number to anotherone
expenses += groceries[user_input]
print("Shopping cart full. You bought {} items and have {} left in your budget.".format(len(cart), budget-expenses))
I've made some changes to your code to make it work, with explanation including using comments indicated by the # symbol.
The two most important things are that all parentheses need to be closed:
fun((x, y) # broken
fun((x, y)) # not broken
and keywords in Python are all lowercase:
if, while, for, not # will work
If, While, For, Not # won't work
You might be confused by True and False, which probably should be lowercase. They've been that way so long that it's too late to change them now.
budget = 100 # You need to initialize variables before using them.
def shoplist():
prices = { # I re-named the price list from list to prices
'apple' : 30, # because list is a reserved keyword. You should only
'orange' : 20, # use the list keyword to initialize list objects.
'milk' : 60, # This type of object is called a dictionary.
} # The dots .... would have caused an error.
# In most programming languages, you need to close all braces ().
# I've renamed buy to item to make it clearer what that variable represents.
item = input('What do you want to purchase? ')
# Also, you don't need to cast the value of input to str;
# it's already a str.
if item in prices:
# If you need an int, you do have to cast from string to int.
count = int(input('How many? '))
cost = count*prices[item] # Access dictionary items using [].
if cost > budget:
print('You can\'t afford that many!')
else:
# You can put data into strings using the % symbol like so:
print('That\'ll be %i.' % cost) # Here %i indicates an int.
else:
print('We don\'t have %s in stock.' % item) # Here %s means str.
shoplist()
A lot of beginners post broken code on StackOverflow without saying that they're getting errors or what those errors are. It's always helpful to post the error messages. Let me know if you have more questions.

Making a statistics program

I am trying to write a Python program that computes and prints the following :
the average score from a list of scores
the highest score from a list of scores
the name of the student who got the highest score.
The program starts by asking the user to enter the number of cases. For EACH case, the program should ask the user to enter the number of students. For each student the program asks the user to enter the student's name and marks. For EACH case the program reports the average marks, the highest marks and the name of the student who got the highest marks.
Also
If there are more than one person with the highest score in a CASE, the program should report the first occurrence only.
The average score and the highest score should have exactly 2 decimal places.
The output should be as in the sample program output.
What I have been trying so far is the following:
grade=[]
name_list=[]
cases=int(input('Enter number of cases: '))
for case in range(1,cases+1):
print('case',case)
number=int(input('Enter number of students: '))
for number in range (1,number+1):
name=str(input('Enter name of student: '))
name_list.append(name)
mark=float(input('Enter mark of student:'))
grade.append(mark)
highest= max (grade)
average=(sum(grade)/number)
high_name=grade.index(max(grade))
print('average',average)
print('Highest',highest)
print (high_name)
This is what i have deciphered so far. my biggest problem now is getting the name of the individual with the high score. Any thoughts and feedback is much appreciated. As with respect to the answer posted below, i am afraid the only thing i do not understand is the dictionary function but otherwise the rest does make sense to me.
This resembles an assignment, it is too specific on details.
Anyways, the official docs are a great place to get started learning Python.
They are quite legible and there's a whole bunch of helpful information, e.g.
range(start, end): If the start argument is omitted, it defaults to0
The section about lists should give you a head start.
numcases = int(input("How many cases are there? "))
cases = list()
for _ in range(numcases):
# the _ is used to signify we don't care about the number we're on
# and range(3) == [0,1,2] so we'll get the same number of items we put in
case = dict() # instantiate a dict
for _ in range(int(input("How many students in this case? "))):
# same as we did before, but skipping one step
name = input("Student name: ")
score = input("Student score: ")
case[name] = score # tie the score to the name
# at this point in execution, all data for this case should be
# saved as keys in the dictionary `case`, so...
cases.append(case) # we tack that into our list of cases!
# once we get here, we've done that for EVERY case, so now `cases` is
# a list of every case we have.
for case in cases:
max_score = 0
max_score_student = None # we WILL need this later
total_score = 0 # we don't actually need this, but it's easier to explain
num_entries = 0 # we don't actually need this, but it's easier to explain
for student in case:
score = case[student]
if score > max_score:
max_score = score
max_score_student = student
total_score += score
num_entries += 1
# again, we don't need these, but it helps to demonstrate!!
# when we leave this for loop, we'll know the max score and its student
# we'll also have the total saved in `total_score` and the length in `num_entries`
# so now we need to do.....
average = total_score/max_entries
# then to print we use string formatting
print("The highest score was {max_score} recorded by {max_score_student}".format(
max_score=max_score, max_score_student=max_score_student))
print("The average score is: {average}".format(average=average))

Categories

Resources