Reputation: 2857
I defined the following function to test if an input is a positive int. I plan on using eval(raw_input("...")) so that's why the try-except part is there:
def is_ok(x): # checks if x is a positive integer
is_int = False
is_pos = False
try:
if type(eval(x)) == int:
is_int = True
if x > 0:
is_pos = True
else:
pass
else:
pass
except NameError:
is_int = False
print "not even a number!"
return is_int, is_pos
if I try to pass a positive int it would return True, True as expected. It returns False, False and the error message for a non-number.
However, for negative numbers it still returns True for checking if it's positive. For example, adding this after the function :
is_int, is_pos = is_ok("-9")
print is_int, is_pos
running prints: True True
Can't understand why that is and would love your help. Even if there are more efficient ways to accomplish this, I'd still like to understand why it produces True True. Thanks!
(This is somewhat of a followup to: Python: How do I assign 2 values I return from a function with 1 input as values outside the function?)
Upvotes: 0
Views: 13314
Reputation: 1
why not make it simple
def is_positive(number):
if number > 0:
return True
else:
if number <= 0:
return False
Upvotes: 0
Reputation: 66
def is_ok(x):
try:
return type(x)==int, int(x)>0
except ValueError:
return False, False
Or:
def is_ok(x):
try:
return type(x)==int, 'Positive' if int(x)>0 else 'Negative'
except ValueError:
return False, 'Neither'
Upvotes: -1
Reputation: 15058
Shorten it down a bit:
def is_ok(x):
is_int = False
is_pos = False
try:
x = float(x)
# Check if the number is integer or not
is_int = x.is_integer()
if x > 0:
is_pos = True
except ValueError:
print("not even a number!")
return is_int, is_pos
To explain how this works, you can pass a string to int()
to convert this to an integer. However, passing an invalid string (like foo
) will raise a ValueError
. We can catch that and display our "not even a number!"
message to the user. Much safer than using eval()
.
Try not to use eval()
unless you absolutely trust the input.
Removing all the variables you can also make it:
def is_ok(x):
try:
# Check if is an integer and greater than 0
return float(x).is_integer(), float(x) > 0
except ValueError:
print("not even a number!")
return False, False
Your original problem was it was returning True, True
for even negative numbers. The problem here is that whilst you were using type(eval(x)) == int
you were then not making x
an integer object. This then has an unexpected effect when you try and compare a string to an integer later on (if x > 0
):
In [9]: "twenty" > 0
Out[9]: True
You can read more about this strange behaviour in this very detailed answer.
If you were to redefine x
as your variable:
try:
x = eval(x)
if type(x) == int:
Then when you made the comparison it would behave better and return True, False
for "-9"
.
Upvotes: 6
Reputation: 122116
This all seems needlessly complicated, and using eval
on raw_input
is a security risk - the user can enter anything they like.
Instead, try something like:
def is_ok(s):
try:
i = int(s)
except ValueError:
return False, False
else:
return True, i >= 0
Example inputs and outputs:
>>> for s in ["foo", "9", "-9"]:
print s, is_ok(s)
foo (False, False)
9 (True, True)
-9 (True, False)
Your error is here:
if x > 0:
Remember x
is still a string, and in Python 2.x all strings will compare > 0
.
Upvotes: 3
Reputation: 16940
>>> def is_int_positive(n):
... try:
... if n == 0:
... return True, 'Positive'
... elif max(0,int(n)):
... return True, 'Positive'
... else:
... return True, 'Negative'
... except:
... return False, 'Error'
...
>>> for i in [1, 0, -23, 23, 'a']:
... print i, is_int_positive(i)
...
1 (True, 'Positive')
0 (True, 'Positive')
-23 (True, 'Negative')
23 (True, 'Positive')
a (False, 'Error')
>>>
Upvotes: 0