This is a piece of code I encountered in the 7th lecture on introduction to computer science on MIT OCW. This small program gets input for base and height then calculate the hypotenuse with Pythagoras theorem.
For some reason, it couldn't recognize entry of float.
The code is as follows:
#! /Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5
import math
#Get base
inputOK = False
while not inputOK:
base = input("Enter base: ")
if type(base) == type(1.0):
inputOK = True
else:
print("Error. Base must be a floating point number.")
#Get Height
inputOK = False
while not inputOK:
height = input("Enter height: ")
if type(height) == type(1.0):
inputOK = True
else:
print("Error. height must be a floating point number.")
hyp = math.sqrt(base*base + height*height)
print("Base: " + str(base) + ", height: " + str(height) + ", hypotenuse:" + str(hyp))
This is one of those cases where it is easier to ask for forgiveness than permission. Instead of trying to look at the object and assert it is a float before you act, try to use it as a float and catch any exceptions.
That is, instead of using ifs use:
try:
base = float(base)
inputOK = True
except ValueError as e:
print("Error. Base must be a floating point number.")
This applies similarly to the height value you're trying to get afterwards.
Regardless, input() returns a string so type(input()) will always return str. It is better to cast it to a float (note: ints are also applicable and will be made to floats) and see if it is acceptable than trying to discern its type with if checks.
Mandatory aside, if you even need to check for types, don't use type(obj_a) == type(obj_b), it is arguably always better to use isinstance(obj_a, type(obj_b)).
The code appears to be written for Python 2, not Python 3, as it requires input() to return something other than a string. In Python 3, input() always returns a string, it never applies eval() to that result like Python 2 would.
It has other issues as well, like using type(base) == type(1.0), completely ignoring the availability of the float object and using is to test for identity, and misses out completely on the far superior isinstance() function.
Just use exception handling instead:
while True:
try:
base = float(input("Enter base: "))
break
except ValueError:
print("Error. Base must be a floating point number.")
Note that there is no need for a inputOK boolean either.
Related
In the second line, I am trying to make it not crash if a string is entered but can't find a way to use an exception or something similar. In the while loop it works normally as the exception deals with this case.
number = 0 #this to be removed
number = (float(input('pick a number'))) #I want to make this not crash if a string is entered.
while number not in [100, 200, 3232]:
try:
print('wrong number ')
number = (float(input('pick a number;'))) #Here it does not crash if a string is entered which is fine
except ValueError:
print("retry")
while followed by a variable condition often ends up with bugs/repeating code => bad maintenability.
Use a while True condition to avoid repeating your code, then break out the loop when it's valid.
while True:
try:
number = float(input('pick a number;'))
if number in [100, 200, 3232]:
break
print("wrong number")
except ValueError:
print("illegal number, retry")
note: be careful with float equality in the general case (see also strange output in comparison of float with float literal, Is floating point math broken?)
Maybe create a function to take input:
def get_input():
while True:
a = input("Pick a number: ")
try:
return float(a)
except:
pass
New to Python and am trying to answer a homework problem where: a hospital records how many patients they are dealing with, the required nutrition to be provided to each patient, and then averaging required nutrition per patient after summing the totals.
Now when I'm testing/validating data entry, I see my code is causing errors because of the clumsy way I've tried to solve the problem. When testing, I get this:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
I've tried going through and messing with the return functions, but if it's not there, I think the issue might be with my read_input() functions. I've been messing around with PythonTutor, so I can visualize where the error is...I just have no idea how to get out of this loop and fix it.
my code so far
def validate_positive_patients(n):
try:
n = float(n)
if n <= 0:
print("Please enter a nonnegative number")
return n, False
except ValueError:
print("Please enter a positive integer")
return None, False
return n, True
def read_input(float):
value, positive = validate_positive_patients(input(float))
if not positive:
read_input(float=float)
else:
return value
# rest of code seems to work fine
My code is clumsy, but what I'd really like it to do is only accept int values for 'number of patients', floats for protein, carbs etc., and if there is an entry error initially to not just spit out a None value.
If only computers knew what you wanted them to do instead of what I'm telling it to do :P
Thanks in advance for any help!
By default, Python functions return None.
In your original code, in read_input, if the value entered is not positive, then you never hit a return statement, and accordingly return None.
I've cleaned up your code a little, while attempting to preserve its spirit:
def get_positive_int(message):
while True:
input_value = input(message)
if input_value.isdigit() and int(input_value) > 0:
return int(input_value)
else:
print('Please enter a positive number.')
def get_positive_float(message):
while True:
input_value = input(message)
try:
float_value = float(input_value)
if float_value > 0:
return float_value
except ValueError:
pass
print('Please enter a positive real number.')
def calculate_average(nutrition, total_quantity, total_patients):
average = total_quantity / total_patients
print(f'{nutrition} {average}')
number_of_patients = get_positive_int("Enter number of patients: ")
protein, carbohydrates, fat, kilojoules = 0, 0, 0, 0
for i in range(int(number_of_patients)):
print(f'Patient {i + 1}')
protein += get_float("Amount of protein (g) required: ")
carbohydrates += get_float("Amount of carbohydrates (g) required: ")
fat += get_float("Amount of fat (g) required: ")
kilojoules += 4.18*(4*protein + 4*carbohydrates + 9.30*fat)
print("Averages:")
calculate_average(nutrition = "Protein (g): ", total_quantity = protein,
total_patients = number_of_patients)
calculate_average(nutrition = "Carbohydrates (g): ", total_quantity =
carbohydrates, total_patients = number_of_patients)
calculate_average(nutrition = "Fat (g): ", total_quantity = fat,
total_patients = number_of_patients)
calculate_average(nutrition = "Kilojoules (kJ): ", total_quantity =
kilojoules, total_patients = number_of_patients)
In particular, it is unwise to shadow builtins (using float as a parameter name), and f-strings can make your code easier to read.
You'd be getting None because you're ignoring a value when you call read_input again in the if statement.
The alternative would be to just loop, not call the same function
def read_input(prompt):
positive = False
while not positive:
value, positive = validate_positive_patients(input(prompt))
return value
And I suggest you use while loops so that it continously checks the results
Note that you're also doing return None, False in the first function, so you still should check that value is not None before actually returning a numeric value
Also Check if input is positive integer
def total():
n = prompt()
answer = (n-2)*180
print ("The polygon has", answer, "sides.")
def prompt():
x = raw_input("Type number: ")
return x
I'm trying to get n which is equal to the output of prompt to be an integer so that math can be done on it. How would I do this?
raw_input returns a string, so you cannot use it for any calculations. If you want to have an integer instead, you can use the int function to convert the value. You can do that either within your prompt function, or later in the calling function (although it would make more sense to have a function that asks the user for a number return one):
def prompt ():
x = raw_input("Type a number: ")
return int(x)
Note, that int() may raise a ValueError for any user entered value that is not a valid integer. In that case, you should catch the exception and prompt the user again to correct the input. See this question on how that would work.
This question already has answers here:
Asking the user for input until they give a valid response
(22 answers)
Closed 8 years ago.
user_input = float(input("Please enter a multiplier!")
if user_input == int:
print " Please enter a number"
else:
for multiplier in range (1,13,1):
print multiplier, "x", user_input, " = ", multiplier * user_input
The program will run effectively, as for any number entered by the user the result will be effective, yet I wish to know a function that allows the user to ask for a number when they enter a letter.
Use a try/except inside a while loop:
while True:
try:
user_input = float(raw_input("Please enter a multiplier!"))
except ValueError:
print "Invalid input, please enter a number"
continue # if we get here input is invalid so ask again
else: # else user entered correct input
for multiplier in range (1,13,1):
print multiplier, "x", user_input, " = ", multiplier * user_input
break
Something that's a float is not an int. They're separate types. You can have a float that represents an integral value, like 1.0, but it's still a float.
(Also, user_input == int isn't checking whether user_input is an int, it's checking whether user_input is actually the type int; you wanted isinstance(user_input, int). But since that still won't work, let's skim over this part…)
So, can you check that a float has an integral value? Well, you can do this:
if int(user_input) == user_input
Why? Because 1.0 and 1 are equal, even though they're not the same type, while 1.1 and 1 are not equal. So, truncating a float to an int changes the value into something not-equal if it's not an integral value.
But there's a problem with this. float is inherently a lossy type. For example, 10000000000000000.1 is equal to 10000000000000000 (on any platform with IEEE-854 double as the float type, which is almost all platforms), because a float can't handle enough precision to distinguish between the two. So, assuming you want to disallow the first one, you have to do it before you convert to float.
How can you do that? The easiest way to check whether something is possible in Python is to try it. You can get the user input as a string by calling raw_input instead of input, and you can try to convert it to an int with the int function. so:
user_input = raw_input("Please enter a multiplier!")
try:
user_input = int(user_input)
except ValueError:
print " Please enter a number"
If you need to ultimately convert the input to a float, you can always do that after converting it to an int:
user_input = raw_input("Please enter a multiplier!")
try:
user_input = int(user_input)
except ValueError:
print " Please enter a number"
else:
user_input = float(user_input)
You could use the assert-statment in python:
assert type(user_input) == int, 'Not a number'
This should raise an AssertionError if type is not int. The function controlling your interface could than handle the AssertionError e.g. by restarting the dialog-function
The code below shows error if a decimal (eg. 49.9) is sent to next variable. Can you please tell me why? Why does int() converts it into an integer?
next=raw_input("> ")
how_much = int(next)
if how_much < 50:
print"Nice, you're not greedy, you win"
exit(0)
else:
dead("You greedy bastard!")
If I dont use int() or float() and just use:
how_much=next
then it moves to "else" even if I give the input as 49.8.
As the other answers have mentioned, the int operation will crash if the string input is not convertible to an int (such as a float or characters). What you can do is use a little helper method to try and interpret the string for you:
def interpret_string(s):
if not isinstance(s, basestring):
return str(s)
if s.isdigit():
return int(s)
try:
return float(s)
except ValueError:
return s
So it will take a string and try to convert it to int, then float, and otherwise return string. This is more just a general example of looking at the convertible types. It would be an error for your value to come back out of that function still being a string, which you would then want to report to the user and ask for new input.
Maybe a variation that returns None if its neither float nor int:
def interpret_string(s):
if not isinstance(s, basestring):
return None
if s.isdigit():
return int(s)
try:
return float(s)
except ValueError:
return None
val=raw_input("> ")
how_much=interpret_string(val)
if how_much is None:
# ask for more input? Error?
int() only works for strings that look like integers; it will fail for strings that look like floats. Use float() instead.
Integers (int for short) are the numbers you count with 0, 1, 2, 3 ... and their negative counterparts ... -3, -2, -1 the ones without the decimal part.
So once you introduce a decimal point, your not really dealing with integers. You're dealing with rational numbers. The Python float or decimal types are what you want to represent or approximate these numbers.
You may be used to a language that automatically does this for you(Php). Python, though, has an explicit preference for forcing code to be explicit instead implicit.
import random
import time
import sys
while True:
x=random.randint(1,100)
print('''Guess my number--it's from 1 to 100.''')
z=0
while True:
z=z+1
xx=int(str(sys.stdin.readline()))
if xx > x:
print("Too High!")
elif xx < x:
print("Too Low!")
elif xx==x:
print("You Win!! You used %s guesses!"%(z))
print()
break
else:
break
in this, I first string the number str(), which converts it into an inoperable number. Then, I int() integerize it, to make it an operable number. I just tested your problem on my IDLE GUI, and it said that 49.8 < 50.
Use float() in place of int() so that your program can handle decimal points. Also, don't use next as it's a built-in Python function, next().
Also you code as posted is missing import sys and the definition for dead