python input check function not being called properly - python

I'm working on a very simple temperature converter in Python (just for practice), and am struggling with some of the UX components. I'd like to have checks in place to continue prompting for variable input when invalid entries are made. My full code is below:
o_temp = ''
def temp_input(o_temp):
o_temp = raw_input('Enter a temperature (round to nearest integer): ')
return o_temp
def temp_input_check(o_temp):
o_temp = list(o_temp)
for i in o_temp:
if i not in '1234567890':
print 'Invalid entry. Please enter only the numerical temperature measurement in integer format.'
temp_input(o_temp)
else:
break
def converter(o_temp):
unit = raw_input('Convert to (F)ahrenheit or (C)elsius? ')
unit = unit.upper()
if unit == 'F' or unit == 'f':
n_temp = (9.0/5.0) * int(o_temp) + 32
print '%d C = %d F' % (o_temp, n_temp)
quit()
elif unit == 'C' or unit == 'c':
n_temp = (5.0/9.0) * (int(o_temp) - 32)
print '%d F = %d C' % (o_temp, n_temp)
quit()
else: #check for valid entry
print 'Invalid entry. Please enter F for Fahrenheit or C for Celsius'
unit_input()
def temp_converter():
#title, call sub-functions
print ''
print 'Temperature Converter'
print ''
temp_input(o_temp)
temp_input_check(o_temp)
converter(o_temp)
temp_converter()
However, when I enter an invalid entry (say, a letter or a combination of letters and numbers) into the o_temp prompt, the code does not seem to recognize that this is invalid and continues with the unit prompt. Am I not correctly returning the variable? What's the issue here? I tried removing the initial o_temp declaration but then I got "NameError: global name 'o_temp' is not defined"
EDIT
I came up with this solution, any further suggestions to refine the code at all?
def converter():
print 'Temperature Converter'
while 1:
temp = raw_input('Starting temperature? ')
try:
temp = float(temp)
except ValueError:
print 'Invalid entry. Please enter only the numerical temperature measurement.'
else:
break
while 1:
unit = raw_input('Convert to Fahrenheit or Celsius? ')
if unit.upper().startswith('F') == True:
print "%f C = %f F" % (temp, temp*9./5+32)
return False
elif unit.upper().startswith('C') == True:
print "%f F = %f C" % (temp, (temp-32)*5./9)
return False
else:
print 'Invalid entry. Please enter F for Fahrenheit or C for Celsius'
converter()

You define some functions, then call temp_coverter(). This function calls temp_input(otemp), sending it an empty string for no reason that I can see, other than the possibility that you're unaware that you can define a function with no parameters. This function then returns a value, which you don't save.
After that, temp_input_check(otemp) is called, which attempts to validate the same empty string. This function's returned value isn't saved, which isn't a big loss, because None isn't a particularly useful value to save.
Then converter(otemp) sends the same old empty string to the actual converter. Mayhem results.
I recommend spending some quality time with the tutorial.
When you're done, the code should look more like this:
def converter():
print 'Temperature Converter'
unit = raw_input('Convert to Fahrenheit or Celsius? ')
while 1:
temp = raw_input('Starting temperature? ')
try:
temp = float(temp)
except ValueError:
print 'Not a valid temperature.'
else:
break
if unit.lower().startswith('f'):
print "%f C = %f F" % (temp, temp*9./5+32)
else:
print "%f F = %f C" % (temp, (temp-32)*5./9)
converter()

Your for loop isn't implemented correctly.
def temp_input_check(o_temp):
o_temp = list(o_temp)
for i in o_temp:
if i not in '1234567890':
print 'Invalid entry. Please enter only the numerical temperature measurement in integer format.'
temp_input(o_temp)
else:
break
You check every character for an invalid entry. If you typed in multiple invalid characters, it'll keep hitting the trigger after you have already determined that the string is invalid!
Also, if your first character is valid, you're telling it to break from the for loop (in your code 1fdsdfdsf would be a valid temperature, because it would skip every character after hitting that else statement and breakout from the loop).
Also, your temp_input doesn't need to accept an argument in the function (you're just gonna return the user's input). You actually want to assign it after you call the function instead of having it as an argument
Also, you're calling temp_input again to get the user input, but not capturing that anywhere with a return - so it's ultimately not doing anything. You should have your function return a True or False, and then catch that on the outside of the checker if you want to have the user try and enter a better temperature:
def temp_input_check(o_temp):
o_temp = list(o_temp)
for i in o_temp:
if i not in '1234567890':
print 'Invalid entry. Please enter only the numerical temperature measurement in integer format.'
return False
else:
pass # nothing is wrong with this character, keep checking
return True # if we hit this line, there were no problem characters
Then, when you call the stuff:
while(1):
o_temp = temp_input()
if temp_input_check(o_temp):
break # this means our o_temp is allllright.
# otherwise, go back to the start of the loop and ask for another temp
converter(o_temp)

because you mentioned 'o_temp' as the function parameter in the end but mentioned it as a empty string at Start. Don't give same names for global & function variables (just to avoid confusion). the function took the o_temp you mentioned above as parameter and neglects the one inside them.
Also the raw_input won't consider the input as string. Try input instead to avoid the sensibility of not using str to correct the loop.
This will do:
def converter():
o_temp = float(raw_input('Enter a temperature (round to nearest integer): '))
for i in str(o_temp):
if i not in ['1','2','3','4','5','6','7','8','9','0','.']:
print 'Invalid entry. Please enter only the numerical temperature measurement in integer format.'
unit = raw_input('Convert to (F)ahrenheit or (C)elsius? ')
if unit in ['f','F']:
n_temp = (9.0/5.0) * float(o_temp) + 32
print '%f C = %f F' % (o_temp, n_temp)
elif unit in ['c','C']:
n_temp = (5.0/9.0) * (float(o_temp) - 32)
print '%f F = %f C' % (o_temp, n_temp)
else: #check for valid entry
print 'Invalid entry. Please enter F for Fahrenheit or C for Celsius'
unit_input()
def temp_converter():
#title, call sub-functions
print ''
print 'Temperature Converter'
print ''
converter()
print temp_converter()

Related

How to use try-except block to validate the input, and use a while statement to prompt the user until a valid input in Python?

my task is to calculate the amount of money in a saving account in two ways and compare the results. It prompt the user for input principle, the interest rate(as a percent), and years of invest.I need to use try-except block to validate the input, and use a while statement to prompt the user until a valid input. I have issue on the validation and while process. When I had invalid input, it didn't print associated exception error as expected.The function parts are Ok, just ignore them. Also, "Going around again" is supposed to print before the next prompt input, but mine appeared by the end of correct input execution. Could you please help me? Thanks.
def calculate_compound_interest(principle, int_rate, years):
value = principle * (1 + int_rate)**years
return value
def calculate_compound_interest_recursive(principle, int_rate, years):
if years == 0:
return principle
else:
recursive_value = calculate_compound_interest_recursive(principle, int_rate, years-1)*
(1+int_rate)
return recursive_value
def format_string_output(value, recursive_value):
return "Interest calculated recursively is {:,.2f} and calculated by original formula is
{:,.2f}.These values are a match.".format(recursive_value,value)
print(__name__)
if __name__ == "__main__":
while True:
principle_input = input("Please input principle:")
interest_rate_input = input("Please input interest rate with %:")
years_input = input("Please input years:")
try:
p = float(principle_input)
i = (float(interest_rate_input.replace("%","")))/100
n = int(years_input)
except ValueError():
print("Error: invalid principle.")
except ValueError():
print("Error: invalid interest rate.")
except ValueError():
print("Error: invalid years.")
else:
print(calculate_compound_interest(p, i, n))
print(calculate_compound_interest_recursive(p, i, n))
print(format_string_output(calculate_compound_interest(p, i, n),
calculate_compound_interest_recursive(p, i, n)))
break
finally:
print("Going around again!")
Note: Finally block runs whenever a try or any except block runs.
The Try-Except blocks need to be paired up, easier to show than explain.
def calculate_compound_interest(principle, int_rate, years):
value = principle * (1 + int_rate)**years
return value
def calculate_compound_interest_recursive(principle, int_rate, years):
if years == 0:
return principle
else:
recursive_value = calculate_compound_interest_recursive(principle, int_rate, years-1)*(1+int_rate)
return recursive_value
def format_string_output(value, recursive_value):
return "Interest calculated recursively is {:,.2f} and calculated by original formula is {:,.2f}.These values are a match.".format(recursive_value,value)
if __name__ == "__main__":
while True:
principle_input = input("Please input principle:")
interest_rate_input = input("Please input interest rate with %:")
years_input = input("Please input years:")
try:
p = float(principle_input)
except ValueError():
print("Error: invalid principle.")
print("Going around again!")
continue
try:
i = (float(interest_rate_input.replace("%","")))/100
except ValueError():
print("Error: invalid interest rate.")
print("Going around again!")
continue
try:
n = int(years_input)
except ValueError():
print("Error: invalid years.")
print("Going around again!")
continue
print(calculate_compound_interest(p, i, n))
print(calculate_compound_interest_recursive(p, i, n))
print(format_string_output(calculate_compound_interest(p, i, n),
calculate_compound_interest_recursive(p, i, n)))
break
Let me know any questions via a comment.

How to prevent printing from previous function in current function?

I'm currently writing a test function for class to test provided cases on provided solution code. However I'm running into an issue where a print statement is executing when I don't want it to.
This is the provided solution that I'm testing:
def alphapinDecode(tone):
phone_num = ''
if checkTone(tone): #or checkTone2
while len(tone) > 0:
# retrieve the first tone
next_tone = tone[0:2]
tone = tone[2:]
# find its position
cons = next_tone[0]
vow = next_tone[1]
num1 = consonants.find(cons)
num2 = vowels.find(vow)
# reconstruct this part of the number -
# multiply (was divided) and add back
# the remainder from the encryption division.
phone = (num1 * 5) + num2
# recreate the number
# by treating it as a string
phone = str(phone)
# if single digit, not leading digit, add 0
if len(phone) == 1 and phone_num != '':
phone = '0' + phone
phone_num = phone_num + phone
# but return in original format
phone_num = int(phone_num)
else:
print('Tone is not in correct format.')
phone_num = -1
return phone_num
Here's the (partially done) code for the test function I have written:
def test_decode(f):
testCases = (
('lo', 43),
('hi', 27),
('bomelela', 3464140),
('bomeluco', 3464408),
('', -1),
('abcd', -1),
('diju', 1234),
)
for i in range(len(testCases)):
if f(testCases[i][0]) == testCases[i][1] and testCases[i][1] == -1:
print('Checking '+ f.__name__ + '(' + testCases[i][0] + ')...Tone is not in correct format.')
print('Its value -1 is correct!')
return None
When executing test_decode(alphapinDecode), I get this:
Tone is not in correct format.
Checking alphapinDecode()...Tone is not in correct format.
Its value -1 is correct!
Tone is not in correct format.
Checking alphapinDecode(abcd)...Tone is not in correct format.
Its value -1 is correct!
As you can see, because of the print statement in alphapinDecode(I think), it is printing an extra "Tone is not in correct format." above the print statement I have written.
How would I prevent this print statement from executing, and why is it printing if the print statement I wrote in my test function doesn't ask for the result of alphapinDecode?
We are not allowed to alter the code of the given solution.
I'm fairly new to stackOverflow, so sorry for any formatting issues. Thank you!
Edit: Fixed the idents of the test_decode function
One easy solution would be to pass an extra parameter say, a boolean variable debug to the function. That would go something like this.
def func1(var1, debug):
if debug:
print("Printing from func1")
# Do additional stuff
Now when you call it. You now have the option of setting the debug variable.
func1("hello", debug=True) # will print the statement
func1("hello", debug=False) # will not print statement.
If you cannot modify the called function. Then you can follow this method. explained by #FakeRainBrigand here.
import sys, os
# Disable
def blockPrint():
sys.stdout = open(os.devnull, 'w')
# Restore
def enablePrint():
sys.stdout = sys.__stdout__
print 'This will print'
blockPrint()
print "This won't"
enablePrint()
print "This will too"

List of objects only saving the last object in Python program

So I have an otherwise easy homework assignment that wants me to input my grades for subjects, etc. The amount of input varies with the number of subjects the user wants to enter. The input works fine, but when I print out the saved values only the ones most recently entered are saved. Here is my code for input:
def gpa_input(classList):
print("please enter how many classes you have")
while True:
try:
numOfClasses = int(input())
except ValueError:
print("please enter a valid number")
continue
else:
break
for i in range (numOfClasses):
classList.append(subject)
print("enter name of " + str(i+1) + "th subject:")
classList[i].name = input()
print("enter num of credits for " + str(i+1) + "th subject:")
while True:
try:
classList[i].credits = int(input())
except ValueError:
print("please enter a valid number")
continue
else:
break
print("enter grade for " + str(i+1) + "th subject:")
while True:
try:
classList[i].gradePercentage = int(input())
except ValueError:
print("please enter a valid number")
continue
else:
break
A subject is a class containing a string value and 2 int values, defined as following:
class subject:
def __init__(name, credits, gradePercentage):
self.name = name
self.credits = credits
self.gradePercentage = gradePercentage
And here is the code that prints out all of this:
def main():
gpa_input(classList)
for i in range (len(classList)):
print(classList[i].name)
print(classList[i].credits)
print(classList[i].gradePercentage)
What is the problem with my code? Am I iterating through something the wrong way, or is there something not getting properly assigned/saved?
You've got into the very common "trap".
The problem is in how you initialize your subject class.
Here you just append a class to the list:
classList.append(subject)
The situation here is the following:
Once you called subject without braces you will have a new object.
But when you call it on the second time - python will not initialize the new object for you and just return the object created on the first step.
So all you need is to properly initialize all subject objects.
Two ways:
1) Remove args from subject definition and make default values are none + add braces to the classList.append(subject)
2) Collect all values in your for loop into variables and at the end of the function initialize you subject class with proper args.

python: Maths quiz- data not being stored

My task is to create a quiz for primary school children. The quiz bit works fine. But I must time how long the child takes and store their 'username' 'correctAnswers' and 'timeTaken' into a .txt file for the specific class the child is in. To do that I ask the child their class number and store their information into the file that was specifically made for that class.
The problems I in counter are:
The time isnt being rounded even though I have timeTaken = round(etime)in my code
raw_input not being defined (I have no idea how else to define it)
The message "Sorry, we can not save your data as the class you entered is not valid." comes up even when a valid class number has been entered.
Ive searched everywhere but with no luck. Any help at all would be greatly appreciated.
import time
import random
import math
def test():
num1=random.randint(1, 10)
num2=random.randint(1, num1)
ops = ['+','-','*']
operation = random.choice(ops)
num3=int(eval(str(num1) + operation + str(num2)))
print ("What is {} {} {}?".format(num1, operation, num2))
userAnswer= int(input("Your answer:"))
if userAnswer != num3:
print ("Incorrect. The right answer is {}".format(num3))
return False
else:
print("correct")
return True
username=input("What is your name?")
print ("Welcome {} to the Arithmetic quiz".format(username))
usersClass = input("Which class are you in? (1,2 or 3)")
raw_input("Press Enter to Start...")
start = time.time()
correctAnswers=0
for question_number in range(10):
if test():
correctAnswers +=1
print("{}: You got {} answers correct".format(username, correctAnswers))
end = time.time()
etime = end - start
timeTaken = round(etime)
print ("You completed the quiz in {} seconds".format(timeTaken))
if usersClass == 1:
with open("class1.txt","a+") as f:
f.write("{}:Scored {} in {} seconds".format(username,correctAnswers,timeTaken))
elif usersClass == 2:
with open("class2.txt","a+") as f:
f.write("{}:Scored {} in {} seconds".format(username,correctAnswers,timeTaken))
elif usersClass == 3:
with open("class3.txt","a+") as f:
f.write("{}:Scored {} in {} seconds".format(username,correctAnswers,timeTaken))
else:
print("Sorry, we can not save your data as the class you entered is not valid.")
The return value of input is a str object:
>>> usersClass = input("Which class are you in? (1,2 or 3)")
Which class are you in? (1,2 or 3)3
>>> type(usersClass)
<class 'str'>
As a result, your subsequent checks against int objects will evaluate to False (ie, '3' != 3) resulting in what you are seeing.
The conditions of comparing which usersClass the user has selected would need to compare the same type to ensure equality. This means you could convert your return value of input to an int and continue to compare usersClass to an int which would satisfy your comparison as your code is written now,
usersClass = int(input("Which class are you in? (1,2 or 3)"))
or change the conditionals to compare usersClass to the str representation of 1, 2 and 3.
if usersClass == '1':
with open("class1.txt","a+") as f:
f.write("{}:Scored {} in {} seconds".format(username,correctAnswers,timeTaken))
...
As to the problem you are experiencing with raw_input using Python 3, it has been renamed to input: (taken from What's New in Python 3.0)
PEP 3111: raw_input() was renamed to input(). That is, the new input()
function reads a line from sys.stdin and returns it with the trailing
newline stripped. It raises EOFError if the input is terminated
prematurely. To get the old behavior of input(), use eval(input()).

Problems transferring information from one part of a function to another

While working on my program I have run into a problem where the information stored in Menu option 1 is not being transferred to Menu option 2. As you can see it is correctly stored when in menu one. When it returns to go to menu option 2 its like it never went to option 1.
update #1:
some suggestions I've had is to understand scope? from what I can tell the program is not passing the data along to its parent program even though I've typed out return in each of the definitions.
#Must be able to store at least 4 grades
#Each class can have up to 6 tests and 8 hw's
#Weighted 40%*testavg 40% hw average attendance is 20%
#User must be able to input a minimum grade warning
#after each test the your program must calculate the students average and issue warning if necessary
##Define the Modules##
import math
def menu (a): #2nd thing to happen
menuend = 'a'
while menuend not in 'e':
menuend = raw_input("Type anything other then 'e' to continue:\n")
print "What would you like to do ?"
menudo = 0
print "1 - Enter Courses\n2 - Select Course to Edit\n3 - Save File\n4 - Load File\n5 - Exit\n"
menudo = input("Enter Selection:")
if (menudo == 1):
menuchck = 0
menuchck = raw_input("\nYou have entered #1 (y/n)?:\n")
if menuchck in ["Yes","yes","y","Y"]:
x = m1()
else:
print "I'm sorry,",nam,",for the confusion, lets try again\n"
menu()
elif (menudo == 2):
menuchck1 = 0
menuchck1 = raw_input("\nYou have entered #2 (y/n)?:\n")
if menuchck1 in ["Yes","yes","y","Y"]:
x = m2()
else:
print "I'm sorry,",nam,",for the confusion, lets try again\n"
menu()
elif (menudo == 3):
print "Entered 3"
elif (menudo == 4):
print "Entered 4"
else:
print "Anything Else Entered"
def course(): #3rd thing to happen
b = {}
while True:
while True:
print "\n",name,", please enter your courses below ('e' to end):"
coursename = raw_input("Course Name:")
if (coursename == 'e'):
break
will = None
while will not in ('y','n'):
will = raw_input('Ok for this name : %s ? (y/n)' % coursename)
if will=='y':
b[coursename] = {}
print "\n",name,", current course load:\n",b
coursechck = None
while coursechck not in ('y','n'):
coursechck = raw_input("Are your courses correct (y/n)")
if coursechck =='y':
return b
else:
b = {}
print
##Menu Options##
def m1():
a = course()
return a
def m2():
print "Excellent",name,"lets see what courses your enrolled in\n"
print x
return x
###User Input Section###
name = raw_input("Enter Students Name:\n")
a = {}
menu(a)
raw_input("This is the end, my only friend the end")
In your if-elif blocks in the do==1 case, you write m1(), but for the last case, you write x=m1(). You should have the latter everywhere (by typing m1() you only run the function, but do not store the returned x anywhere).
By the way, you can avoid this if-elif confusion using if chck in ["Yes","yes","Y","y"]:

Categories