Reputation: 498
I am trying to add two numbers, even if they contain "-" or ".", but my if command is wrong somehow, here is the code:
def add():
print "\nAddition"
print " "
print "What is your first number?"
preadd1=raw_input(prompt)
print "What is your second number?"
preadd2=raw_input(prompt)
if preadd1.isdigit() and preadd2.isdigit():
add1=int(preadd1)
add2=int(preadd2)
add_answer= add1+add2
print " "
print add_answer
add()
elif preadd1=="pike" or preadd2=="pike":
pike()
elif "-" in preadd1 or "." in preadd1 or "-" in preadd2 or "." in preadd2 and preadd1.replace("-","").isdigit() and preadd1.replace(".","").isdigit() and preadd2.replace("-","").isdigit() and preadd2.replace(".","").isdigit():
add1=float(preadd1)
add2=float(preadd2)
add_answer=add1+add2
print ""
print add_answer
add()
else:
print "\nPlease enter two numbers."
add()
add()
when I enter a non-number like "-sf" it returns the error:
ValueError: could not convert string to float: -sf
this makes no sense to me, seeing as a made sure preadd1.replace("-","").isdigit() and preadd1.replace(".","").isdigit() and preadd2.replace("-","").isdigit() and preadd2.replace(".","").isdigit()
Please help.
Upvotes: 0
Views: 112
Reputation: 893
As Bill said, your if statement is short-circuiting, which means as soon as the first statement in an or
pair is True
, the entire statement immediately evaluates to True
. I feel I should also note that, according to the docs, and
is evaluated before or
, which could also be causing some problems. You could possibly fix this with some well-placed parentheses, but if I may propose an alternative:
#!/usr/bin/env python
def add():
print "\nAddition\n"
print "What is your first number?"
prompt=""
preadd1=raw_input(prompt)
print "What is your second number?"
preadd2=raw_input(prompt)
add1=toint(preadd1)
add2=toint(preadd2)
add1f=tofloat(preadd1)
add2f=tofloat(preadd2)
if (add1 is not None) and (add2 is not None):
add_answer=add1+add2
print " "
print add_answer
add()
elif (add1f is not None) and (add2f is not None):
add_answer=add1+add2
print ""
print add_answer
add()
elif preadd1=="pike" or preadd2=="pike":
pike()
else:
print "\nPlease enter two numbers."
add()
def toint(x):
try:
return int(x)
except ValueError:
return None
def tofloat(x):
try:
return float(x)
except ValueError:
return None
if __name__ == "__main__":
add()
The functions toint()
and tofloat()
first try to convert the input to their corresponding type. If a ValueError
occurs inside the try
block (meaning the input was not a valid int
or float
), then the except
block catches the error and instead returns None
.
I would also like to point out that this is not necessarily the best use of recursion, but since I assume this is just a "learning the language" type of project I left it in my code as well. It would probably be better to use a while
loop instead of recursion in this case.
Edit: Code edited to include elif
statements since we don't know what's in pike()
. Kudos @BillLynch.
Upvotes: 0
Reputation: 51000
Your immediate problem is a failure to understand how Python is making logical sense of the conditions in your if statement. You want Python to evaluate all the or
s and then move on to the and
s but that's not how Python works.
What you think you wrote:
("-" in preadd1 or "." in preadd1 or "-" in preadd2 or "." in preadd2)
and
(preadd1.replace("-","").isdigit() and preadd1.replace(".","").isdigit()
and preadd2.replace("-","").isdigit() and preadd2.replace(".","").isdigit())
What Python saw:
("-" in preadd1)
or
("." in preadd1)
or
("-" in preadd2)
or (
"." in preadd2 and preadd1.replace("-","").isdigit() and preadd1.replace(".","").isdigit()
and preadd2.replace("-","").isdigit() and preadd2.replace(".","").isdigit()
)
Looked at this way, you'll see that Python never read past the very first condition ("-" in preadd1
) before deciding the entire condition is True and continuing with the indented block.
You can use parentheses to bind the operators correctly and get the result you want. But you should be troubled by that extensive test to determine whether the string can be converted to a float. At the very, very least it should be factored out into a function or method with a name that indicates what you're doing but it's more typical to do something like this in Python:
try:
fl1 = float(preadd1)
except:
fl1 = None
try:
fl2 = float(preadd2)
except:
fl2 = None
if fl1 is not None and fl2 is not None:
# Do your float logic here
else:
# Do your non-float logic here
Upvotes: 0
Reputation: 14619
Instead of trying to predict what text is appropriate for float
conversion, just do it and handle the consequences.
See also: EAFP
Incomplete snippet illustrating concept:
while True:
try:
text = raw_input()
val = float(text)
break
except ValueError as e:
continue
Upvotes: 2
Reputation: 81996
Let's reduce your code example to what you're actually concerned about:
preadd1 = "-sf"
preadd2 = "3"
if "-" in preadd1 or "." in preadd1 or "-" in preadd2 or "." in preadd2 and preadd1.replace("-","").isdigit() and preadd1.replace(".","").isdigit() and preadd2.replace("-","").isdigit() and preadd2.replace(".","").isdigit():
print "Shouldn't get here!"
Here's your expression:
if "-" in preadd1 or "." in preadd1 or "-" in preadd2 or "." in preadd2 and preadd1.replace("-","").isdigit() and preadd1.replace(".","").isdigit() and preadd2.replace("-","").isdigit() and preadd2.replace(".","").isdigit():
There's a -
in your string, so that whole expression is true.
You should look at this question for a variety of correct ways to test if a string can be converted to a float: Checking if a string can be converted to float in Python
Upvotes: 2
Reputation: 1455
Try wrapping your raw_input()
s in int()
. You'll need to catch the error so that it doesn't make it to the if
.
Upvotes: 0