Simplifying user-input foolproofing, Python - python

I have the following code to make sure that a user enters a float in python:
while True:
try:
some_variable = int(input("Input Prompt: "))
break
except ValueError:
print("Please enter a whole number (in digits)")
The code works fine, but I have a program that needs many of these, and I was wondering if there is a way to simplify it.
ie I wouldn't have to use:
while True:
try:
some_variable = int(input("Input Prompt: "))
break
except ValueError:
print("Please enter a whole number (in digits)")
For every user input. I'd really appreciate any help I can get.

Perhaps you can use https://github.com/asweigart/pyinputplus to specify what ranges or inputs are valid?

Ok, I did some research on Thierry Lathuille's suggestion. I used functions to simplify the code. Below is the simplified code for everyone's use:
def int_input(prompt):
while True:
try:
variable_name = int(input(prompt))
return variable_name
except ValueError:
print("Please enter a whole number (in digits)")
def float_input(prompt):
while True:
try:
variable_name = float(input(prompt))
return variable_name
except ValueError:
print("Please enter a number (in digits)")
def yes_input(prompt):
while True:
variable_name = input(prompt).lower()
if variable_name in ["y", "yes"]:
return "yes"
elif variable_name in ["n", "no"]:
return "no"
else:
print("""Please enter either "yes" or "no": """)
while True:
print("Volume of a right circular cone")
print("Insert the radius and height of the cone below:")
one_third = 1 / 3
radius = float_input("Radius: ")
height = float_input("Perpendicular Height: ")
pi_confirm = yes_input("""The value of π is 22/7, "yes" or "no": """)
if pi_confirm == "yes":
pi = 22/7
if pi_confirm == "no":
pi = float_input("Type the value of pi, for eg ➡ 3.141592653589: ")
volume = one_third * pi * radius ** 2 * height
accuracy = int_input("How many decimal places do you want your answer to?: ")
print(f"""{volume:.{accuracy}f}""")
new_question = yes_input("""New question? "yes" or "no": """)
if new_question == "no":
break
Again thanks for your help.
Also if anyone has any more suggestions for the code I'd really appreciate it if you leave a comment.

Related

Why isnt the indexing in this python script working?

I'm writing this script for an assignment so I'd appriciate being talked through it rather than simply being handed an answer. Basically I'm trying to convert feet to meters, meters to feet, and provide a sum of the total converted distance in both at the end. Without the [] indexes, It was working perfectly. The new part I've only just added and am struggling with is the [] indexes, and to be honest I'm having a hell of a time groking how they work. Anyways heres the code:
MAX = 256
switch = ""
feet = [0.0] * MAX
meters = [0.0] * MAX
feetpermeter = 3.28084
metersperfoot = 0.3048
sum_meters = 0
sum_feet = 0
def main():
selector()
def selector():
while True:
print("Is your measurement in meters or feet?")
switch = input("Or would you like to quit?")
if (switch == "feet" or switch == "Feet"):
ftm()
elif (switch == "meters" or switch == "Meters"):
mtf()
elif (switch == "quit" or switch == "Quit"):
end()
else:
print("Sorry, that wasn't one of the options.")
print("Lets try that again")
def mtf():
try:
meters[sum_meters] = float(input("Enter the number of meters. "))
feet[sum_feet] = meters * feetpermeter
print("That is", feet, "feet.")
main()
except:
print("Sorry, I didn't quite get that, lets try again.")
mtf()
def ftm():
try:
feet[sum_feet] = float(input("Enter the number of feet. "))
meters[sum_meters] = feet * metersperfoot
print("That is", meters, "meters.")
main()
except:
print("Sorry, I didn't quite get that, lets try again.")
ftm()
def end():
while True:
switch2 = input("Are you sure you want to quit(y/n)?")
if (switch2 == "y" or switch2 == "Y"):
print("you converted a total of ", sum(feet), "feet")
print("And", sum(meters), "meters.")
print("Bye!")
exit()
elif (switch2 == "n" or switch2 == "N"):
print("Ok, let's try that again.")
main()
else:
print("Sorry, that wasn't one of the options.")
print("Lets try that again")
main()
I did try having sum_feet + 1 and sum_meters + 1 after each result but that hadnt worked either.
You are not using the indexing in a proper way. For instance , look at the comments on your existing code:
def mtf():
try:
# Error 1. You stored all the inputs to index 0, as sum_meters is 0 always and its not incremented
# So, all the inputs are not recorded, only last one gets in index 0
meters[sum_meters] = float(input("Enter the number of meters. "))
# Error 2: You multiplied the whole list against the conversion parameter.
# Instead, you should multiply the value at current index
feet[sum_feet] = meters * feetpermeter
# This will print the whole list. Again use the current index here
print("That is", feet, "feet.")
main()
except:
print("Sorry, I didn't quite get that, lets try again.")
mtf()
A fixed version of your function will be like:
def mtf():
try:
# For modifying global variables in a function scope
global sum_meters
global sum_feet
meters[sum_meters] = float(input("Enter the number of meters. "))
feet[sum_feet] = meters[sum_meters] * feetpermeter
print(f"That is {feet[sum_feet]} feet.")
sum_meters += 1
sum_feet += 1
main()
except:
print("Sorry, I didn't quite get that, lets try again.")
mtf()
This fixes stands true for your other functions as well.
I also thought to give you another piece of advice, that you can use a good object oriented approach for such problems, which makes it simpler to implement. You can learn a lot about that, then you will feel more confident.
As an example, see the below code - which does almost same, but in a more crisp way.
class Converter:
FEET_PER_METER = 3.28084
METERS_PER_FOOT = 0.3048
def __init__(self):
self.feet_store = []
self.meter_store = []
self.curr_index = 0
self.menu_handlers = {
"feet": self.feet_to_meter,
"meters": self.meter_to_feet,
"quit": self.summary
}
def run_selection(self, selected):
#
selected = str.lower(selected)
if selected in self.menu_handlers:
# call the relevant function
return self.menu_handlers.get(selected)()
return False
def meter_to_feet(self):
meters_in = float(input("Enter the number of meters."))
to_feet = meters_in * self.FEET_PER_METER
self.meter_store.append(meters_in)
self.feet_store.append(to_feet)
print(f"In Feet : {to_feet}")
return to_feet
def feet_to_meter(self):
feet_in = float(input("Enter the number of feet."))
to_meters = feet_in * self.METERS_PER_FOOT
self.feet_store.append(feet_in)
self.meter_store.append(to_meters)
print(f"In Meters : {to_meters}")
return to_meters
def summary(self):
confirm = input("Are you sure you want to quit(y/n)?")
if confirm in ["y", "Y"]:
print("you converted a total of ", sum(self.feet_store), "feet")
print("And", sum(self.meter_store), "meters.")
print("Bye!")
exit()
else:
return False
def main():
converter = Converter()
while True:
choice = input("Is your measurement in meters or feet (meters/feet/quit)?")
converter.run_selection(choice)
I hope this gives you better insights.
So theres two problems with what you've tried to do here, in the lines:
meters[sum_meters] = float(input("Enter the number of meters. "))
feet[sum_feet] = meters * feetpermeter
meters * feetpermeter is multiplying an array by a number, you need to do meters[sum_meters] to get the number you want. Secondly as you said, you need to increment sum_meters each time, but because you're inside a function you will need to declare the variable as a global before you change it. Also since sum_meters and sum_feet are always going to be equal, you can just use a single variable to keep track of this:
def mtf():
try:
global index
meters[index] = float(input("Enter the number of meters. "))
feet[index] = meters[index] * feetpermeter
index += 1
print("That is", feet, "feet.")
main()
except:
print("Sorry, I didn't quite get that, lets try again.")
mtf()
def ftm():
try:
global index
feet[index] = float(input("Enter the number of feet. "))
meters[index] = feet * metersperfoot
index += 1
print("That is", meters, "meters.")
main()
except:
print("Sorry, I didn't quite get that, lets try again.")
ftm()
I would also go a little further and say that the use of lists is unnecessary for this problem, you could simply have two numbers, total_meters and total_feet and add the values as you go. This would take less memory and also remove the arbitrary limit of 256 goes that has been imposed. So I would do:
import sys
MAX = 256
switch = ""
total_feet = 0
total_meters = 0
feetpermeter = 3.28084
metersperfoot = 0.3048
sum_meters = 0
sum_feet = 0
index = 0
def main():
selector()
def selector():
while True:
print("Is your measurement in meters or feet?")
switch = input("Or would you like to quit?")
if switch == "feet" or switch == "Feet":
ftm()
elif switch == "meters" or switch == "Meters":
mtf()
elif switch == "quit" or switch == "Quit":
end()
sys.exit(0)
else:
print("Sorry, that wasn't one of the options.")
print("Lets try that again")
def mtf():
try:
global total_feet
global total_meters
meters = float(input("Enter the number of meters. "))
feet = meters * feetpermeter
total_meters += meters
total_feet += feet
print("That is", feet, "feet.")
main()
except Exception as e:
print(e)
print("Sorry, I didn't quite get that, lets try again.")
mtf()
def ftm():
try:
global total_feet
global total_meters
feet = float(input("Enter the number of feet. "))
meters = feet * metersperfoot
total_meters += meters
total_feet += feet
print("That is", meters, "meters.")
main()
except Exception as e:
print(e)
print("Sorry, I didn't quite get that, lets try again.")
ftm()
def end():
while True:
switch2 = input("Are you sure you want to quit(y/n)?")
if switch2 == "y" or switch2 == "Y":
print("you converted a total of ", total_feet, "feet")
print("And", total_meters, "meters.")
print("Bye!")
exit()
elif switch2 == "n" or switch2 == "N":
print("Ok, let's try that again.")
main()
else:
print("Sorry, that wasn't one of the options.")
print("Lets try that again")
main()

How to check is an input that is meant to be an integer is empty(in python)?

def aboveIntegerInput(output_message="Enter your number: ", error_1="Please enter a number above {}!", error_2="Integers only!(Please do not leave this blank)", above=0):
while True:
try:
user_input = int(input(output_message))
if user_input >= above:
return int(user_input)
break
else:
print(error_1.format(above))
except ValueError:
print(error_2)
As you can see here the code is supposed to check if an input is an integer and it is above a certain value which by default is 0, but could be changed.
When the user inputs random letters and symbols it see that there is a value error and returns "Integers only!(Please do not leave this blank)".
I want to be able to check if the user inputs nothing, and in that case only it should output "This is blank/empty", the current way of dealing with this is to not check at all and just say "Integers only!(Please do not leave this blank)", in case there us a value error. I want to be able to be more specific and not just spit all the reasons at once. Can anyone please help me?
Thanks in advance.
You could do something like this :
def aboveIntegerInput(output_message="Enter your number: ", error_1="Please enter a number above {}!", error_2="Integers only!", above=0, error_3="Please do not leave this blank"):
while True:
user_input = input(output_message)
try:
user_input = int(user_input)
if user_input >= above:
return user_input
break
else:
print(error_1.format(above))
except ValueError:
if(not user_input):
print(error_3)
else:
print(error_2)
I moved the input outside the try/except block to be able to use it in the except ! This worked fine for me, I hope this is what you needed.
You could just break the input and the conversion to int into two steps, like this:
def aboveIntegerInput(output_message="Enter your number: ", error_1="Please enter a number above {}!", error_2="Integers only!(Please do not leave this blank)", above=0):
while True:
try:
user_input = input(output_message)
if not user_input:
print("Please do not leave this blank")
continue
user_input = int(user_input)
if user_input >= above:
return int(user_input)
break
else:
print(error_1.format(above))
except ValueError:
print(error_2)

How to create a function in Python?

I am new to coding and I am learning python. I’m trying to write a simple program to test my skills, but I’m having some difficulties with it; I want to turn it into a function in order to make the program cleaner, but I get this error: http://prntscr.com/im5pt7
Here is what I want to put inside a function:
name = input(str("\nFull Name: "))
position = input(str("Position at the company: "))
print("\nConfirm Staff Data:\n")
name_confirm = "Name: %s"%(name)
position_confirm = "Position: %s"%(position)
print(name_confirm)
print(position_confirm)
confirmAns = input("Is the information right? (Y/N)")
if confirmAns == "y" or confirmAns == "Y":
message = "\nSearching for %s"%(name)
print(message)
hoursWorked = int(input("Insert hours worked: "))
if hoursWorked <= 0:
print("Please insert a valid number")
elif hoursWorked > 0:
print("\nCalculete Paycheck")
hourRate = int(input("Insert the rate of each hour worked: "))
bonus = input("If a bonus was given insert it here: ")
fine = input("If a fine was given insert it here: ")
print('\n')
payment = hoursWorked*hourRate-int(fine)+int(bonus)
paymentMsg = "Your Payment is: $%d"%(payment)
print(paymentMsg)
elif confirmAns == "n" or confirmAns == "N":
ctypes.windll.user32.MessageBoxW(0, "The software will close to avoid slowness.", "Warning", 1)
else:
print("Please answer with Y or N")
I've tried this but it did not work.
Here is all the code (working but with out the function so I need to copy and paste code): https://pastebin.com/PA9mxMkk
What is happening is that the function as other statements needs to hold it's code into a new indentation level
print('a')
def test(var):
print(var)
not this way
print('a')
def test(var):
print(var)
because this way it will give you the error that you are seeing.
All python code should be indented after the ':' character, in python the indentation should be 4 spaces, or people use the tab key, your code has an issue with indentation which I can't be bothered finding;
for example a 'class'
class this_is_a_class():
#indentation
#code goes here
pass
or a 'for loop' or 'while loop';
numbers = [0,1,2,3,4,5,6,7,8,9]
for number in numbers:
#indentation
print(number)
x = 0
while x < 10:
#indentation
x += 1
print('This is going to print 10 times')
or an 'if statement';
true_boolean = True
if true_boolean:
#indentation
print(True)
or a 'function';
def function():
#indentation
print('You have called a function')
What is actually happening, is python is reading through your code 'Token' by token and 'interpreting' what your code does. But considering you don't know what a function is; gloss over this paragraph.
Now for your question about how functions work. A function is used organize code. You can call a function multiple times, which makes your code more organized and easier to work with, this is why as your code got longer, you ran into this problem; Lets for example say i wanted to print 'hello world' 10 times.
I could write this code on 10 seperate lines;
print("hello world")
print("hello world")
#etc... More chance for error
or I could use a function and call it 10 times;
def say_hello_world():
#indentation
print("hello world")
for each_call in range(0,10):
say_hello_world() #This is the function call
You can also pass 'arguments into a function' for example;
def say_hello(person):
#indentation
print('hello', person)
say_hello('Alex')
Now any words that are in quotations in this answer can be google searched with the word 'python' and you can find out much more about how python works.
I hope this gets you started with python. Although all of these concepts can be used in other programming languages.
The first step which is often difficult in learning python in understanding indentation.
for example.
def hello_world(world):
print("hello ", world)
#your function code goes here.
#you need to indent back to be out of function block.
hello_world("there!")
out: hello there
so in your case it should be like this.
def AnsNo():
name = input(str("\nFull Name: "))
position = input(str("Position at the company: "))
print("\nConfirm Staff Data:\n")
name_confirm = "Name: %s"%(name)
position_confirm = "Position: %s"%(position)
print(name_confirm)
print(position_confirm)
confirmAns = input("Is the information right? (Y/N)")
if confirmAns == "y" or confirmAns == "Y":
message = "\nSearching for %s"%(name)
print(message)
hoursWorked = int(input("Insert hours worked: "))
if hoursWorked <= 0:
print("Please insert a valid number")
elif hoursWorked > 0:
print("\nCalculete Paycheck")
hourRate = int(input("Insert the rate of each hour worked: "))
bonus = input("If a bonus was given insert it here: ")
fine = input("If a fine was given insert it here: ")
print('\n')
payment = hoursWorked*hourRate-int(fine)+int(bonus)
paymentMsg = "Your Payment is: $%d"%(payment)
print(paymentMsg)
elif confirmAns == "n" or confirmAns == "N":
print("working")
else:
print("Please answer with Y or N")
return

How to validate a users input to Numbers only?

I need help validating the input from the (random) questions I ask to make sure that the users input is only a number, rather than letters or any other random character. Also along with the validation there should be an error message notifying the user theyve done something wrong as well as repeat their chance to do the question.
So far the section of my code I need validating is the following:
def quiz():
x = random.randint(1, 10)
y = random.randint(1, 10)
ops = {'+': operator.add,'-': operator.sub,'*': operator.mul}
keys = list(ops.keys())
opt = random.choice(keys)
operation = ops[opt]
answer = operation(x, y)
print ("\nWhat is {} {} {}?".format(x, opt, y))
userAnswer= int(input("\nYour answer: "))
if userAnswer != answer: #validate users answer to correct answer
print ("\nIncorrect. The right answer is",answer,"")
print ("\n============= 8 =============")
return False
else:
print("\nCorrect!")
print ("\n============= 8 =============")
return True
for i in range(questions): #ask 10 questions
if quiz():
score +=1
print("\n{}: You got {}/{} questions correct.".format(name, score, questions,))
Thanks in advance!
Use try...except:
while True:
userAnswer = input("\nYour answer: ")
try:
val = float(userAnswer)
break
except ValueError:
print("That's not a number!")
If you want only integers, use int instead of float.
in Single line :
assert input('Enter Number: ').isdigit()
You may use function validate integer input:
def int_validation(user_Input):
try:
val = int(user_Input)
except ValueError:
print(user_Input,' not an integer!')
It would be good to make a function to accept your input. This can then keep prompting the user until a valid number is entered:
def get_number(prompt):
while True:
try:
return int(input(prompt))
except ValueError:
print("Please enter a number")
You can then change your input line as follows:
userAnswer = get_number("\nYour answer: ")

How to check user input (Python)

I have seen many answers to this question but am looking for something very specific. What I need to accomplish (in pseudo code) is this:
> FOR every ITEM in DICTIONARY, DO:
> PROMPT user for input
> IF input is integer
> SET unique-variable to user input
I'm very new to Python so the code may not be proper, but here is what I have:
def enter_quantity():
for q in menu:
quantities[q] = int(input("How many orders of " + str(q) + "?: "))
So this does everything but evaluate the user input. The problem I'm having is if the input is incorrect, I need to re-prompt them for the same item in the top-level for loop. So if it's asking "How many slices of pizza?" and the user inputs "ten", I want it to say "Sorry that's not a number" and return to the prompt again of "How many slices of pizza?".
Any/all ideas are appreciated. Thanks!
My final solution:
def enter_quantity():
for q in menu:
booltest = False
while booltest == False:
inp = input("How many orders of " + str(q) + "?: ")
try:
int(inp)
booltest = True
except ValueError:
print (inp + " is not a number. Please enter a nermic quantity.")
quantities[q] = int(inp)
You need a while loop with a try/except to verify the input:
def enter_quantity():
for q in menu:
while True:
inp = input("How many orders of {} ?: ".format(q))
try:
inp = int(inp) # try cast to int
break
except ValueError:
# if we get here user entered invalid input so print message and ask again
print("{} is not a number".format(inp))
continue
# out of while so inp is good, update dict
quantities[q] = inp
This bit of code is a little more useful if a menu is added otherwise it crashes at the first hurdle. I also added a dictionary to store the input values.
menu = 'pizza', 'pasta', 'vino'
quantities = {}
def enter_quantity():
for q in menu:
while True:
if q == 'pizza':
inp = input(f"How many slices of {q} ?: ")
elif q == 'pasta':
inp = input(f"How many plates of {q} ?: ")
elif q == 'vino':
inp = input(f"How many glasses of {q} ?: ")
try:
inp = int(inp) # try cast to int
break
except ValueError:
# exception is triggered if invalid input is entered. Print message and ask again
print("{} is not a number".format(inp))
continue
# while loop is OK, update the dictionary
quantities[q] = inp
print(quantities)
Then run the code from this command:
enter_quantity()

Categories