I wish to find a way to achieve the following: With the likes of 5.0, return 5. With the likes of 5.1, which cannot equal any integer, return Error.
Currently I use int() together with an "if integer != float". However this has problems, for instance I won't be able to tell whether the inequality was caused by the likes of 5.1 or the likes of 1111111111111111.0(and even larger numbers).
Also this is extremely troublesome compared with a potential, simple, one-line command. So is there a command in Python that does this?
Float objects in Python have an is_integer() predicate.
def strict_int(x):
if x.is_integer():
return int(x)
raise ValueError
Note that int objects do not have this method. You'll get an attribute error if you try to call this on an int.
If you wanted some error value instead of an exception, you can use a one-liner like this
int(x) if x.is_integer() else 'Error'
Simply use math as suggested in this answer by #Anthony V like this:
>>> frac, whole = math.modf(5.0)
>>> if frac ==0.0:
... print("this is a whole")
... else:
... print("this is not whole and should return the Error")
This should work easily.
I'm not sure whether there's a more idiomatic way to do this, but intuitively, you can just compare the value of the int and the float and return only when they are equal.
That is
def weird_cast(my_float):
if int(my_float) == my_float:
return int(my_float)
return None # or some error
def return_int(a):
if int(a)==a:
print(int(a)) #you can store the integer value in separate variable #also b = int(a)
#instead of using print you can use return b or int(a)
else:
print('Error') #or you can use return 'Error'
a = 5.0
return_int(a)
Maybe another easier way is to minus with the round down number with itself.
if the remainder is more than 0.0 and less than 1.0, then we can call it a float otherwise integer
def IntegerSanityCheck ( num ):
remainder = abs ( round ( num ) - num )
if ( remainder > 0.0 ) and ( remainder < 1.0 ):
print "Float"
else:
print "Integer"
or you can use math as suggested by user2906838
Related
I wish to cast a string or a number to an integer only if the casting is "lossless" or, another way to put it, only if the string or number is indeed an integer.
For instance,
3.0 (a float that is indeed an integer) -> 3.
'3.000' (a string that is an integer) -> 3.
3.1 -> exception raised.
'4.2' -> exception raised.
Directly doing int(x) will convert 3.1 to 3.
This is the best I have:
def safe_cast_to_int(x):
int_x = int(x)
if np.issubdtype(type(x), np.floating):
assert int_x == x, \
f"Can't safely cast a non-integer value ({x}) to integer"
return int_x
but I wonder if there is a better or more Pythonic way?
If I understand you correctly, you only want to cast something if it's a whole number.
If that's the case, you could first cast it to a float and then check with float.is_integer() function if it's an integer.
Here are the examples with values of the question.
>>> float('3.0').is_integer()
True
>>> float('3.000').is_integer()
True
>>> float('3.1').is_integer()
False
>>> float('4.2').is_integer()
False
You could convert to float and modulus the data with 1 to check if you want to keep it a float
val = float(src)
val = int(val) if not val%1 else val
Edit: is_integer() is just doing the below for you, but with a bunch of conditions and flags attached before it gets to this line.
o = (floor(x) == x) ? Py_True : Py_False;
If you want things that look like integers, but aren't really integer values, as in (1.03-0.42)*100, then you need to test to see how "near" an integer a value is, and accept anything close. How close you accept as "integer" will depend on your exact use case:
import sys
tests = [
42,
'1.00',
3.2,
(1.03-0.42)*100,
]
for x in tests:
is_close_to_int = abs(int(float(x))-float(x))<0.00000000001
print(f"{x}: {float(x).is_integer()} {is_close_to_int}")
This outputs:
42: True True
1.00: True True
3.2: False False
61.00000000000001: False True
Showing that for many cases float's is_integer helper will do the right thing, but for some edge cases, a person might expect different results.
The aim is to return the middle letter of a string, or " " if the string's even. I'm failing to see why my code doesn't work. Any sort of clarification would be great, thanks!
def mid(ml):
x=len(ml)
y=x+1
z=y/2
if isinstance(z,int)==True:
return (ml[z-1])
else:
return (" ")
print (mid("abc"))
/ doesn't return an int; even if the number it returns can be represented as one:
>>> 4 / 2
2.0 # A float
It would be better to explicitly check if the number is even or not:
# Read as: "If z is odd", or, "If division of z by 2 has a remainder of 1"
if z % 2 == 1:
return ml[z-1]
else:
return " "
This behavior occurs, because the / operator returns a float. Although the smarter way to solve this would be the use of the modulo operator, if you want to stick to your code, could use the is_integer() method of float like this:
def mid(ml):
x=len(ml)
y=x+1
z=y/2
if z.is_integer():
return (ml[int(z)-1])
else:
return (" ")
print (mid("abc"))
Better way to do it:
def mid(ml):
return ml[len(ml)//2] if len(ml) % 2 else ""
Following the answer from #Carcigenicate above you can try following code:
def mid(ml):
x=len(ml)
y=x+1
z=y/2
return (ml[int(z-1)])
print (mid("abc"))
I've been struggling with the following Boolean problem:
Write a function even_int that consumes any type of data, produces True if it is an even integer, and produces False otherwise.
I wrote:
def even_int(any):
return type(any) != type("a") and float(any % 2 == 0.0)
Feedback on your program:
Make sure your function works when the input is a floating point number.
Don't really understand this feedback. I put the float in front so that should be covered. I also tried without the float or the decimal on the 0.
I think you should just directly check if any is an integer type. I also don't think you need to put a float around any % 2 == 0
def even_int(value):
return isinstance(value, int) and value % 2 == 0
EDIT:
if you want to accept floats as well,
def even_int(value):
return isinstance(value, (float, int)) and value % 2 == 0
I would try this - it's pythonic in that it asks for forgiveness rather than permission by trying to convert to an int (this means it works for strings as well) and catches the TypeError to return False if that doesn't work either.
def even_int(v):
try:
return int(v) % 2 == 0 #will trigger exception if v cannot be cast to int
except (TypeError, ValueError):
return False
EDIT: Simplified based on comments
Im trying to decide whether a string variable is a valid integer or float, ive tried try statements but using ASCII seems to be better. I can't get this to work, probably something with the returns and boolean.
def validation(valid):
var=input("no...")
state=True
y=0
for x in range(len(var)):
if state==False or y==2:
valid=False
return valid
if var[x] == chr(46) or chr(48) <= var[x] <= chr(57):
if var[x] == chr(46):
y+=1
state=True
else:
state=False
valid=True
valid = validation(valid)
print(valid)
The ASCII characters 46 and 48-57 are a decimal point and numbers 0-9. If there more than one decimal point (representing by y) than it also returns a false statement.
Simple and powerful approach:
def isNum(txt):
try:
float(txt)
return True
except ValueError:
return False
There is a much simpler way to do this:
try:
float(x)
except ValueError as e:
print e
print "Not a float"
else:
try:
int(x)
except ValueError as e:
print e
print "not an integer"
You can combine these into a method pretty easily.
Your code isn't very efficient, and it doesn't handle negative numbers, or floats written in scientific notation. Using try, as in fiacre's answer is the standard way to do this in Python.
But to answer your question, you don't have a return statement after the for loop, so if all your tests succeed your function returns the default value of None. So you just need to put a return True at the end of your function.
You can make your code a little more efficient by iterating over the string values and testing the characters directly rather than indexing into the string and using chr(). Eg,
for c in var:
if c == '.' or '0' <= c <= '9':
# etc
Alternatively,
valid_chars = set('-.0123456789')
for c in var:
if c in valid_chars:
# etc
FWIW, in your existing code Python has to re-calculate chr(46) etc on every loop. Sure, that's a pretty fast operation, but it's still wasteful.
Also, there's no need to have both state and valid in the function.
I wanted to create simple code to test if number is odd or even.
I am using Python 2.7.3.
def oddoreven(a):
try: int(a)
except: return "Error"
if a%2==0: return 1
else: return 0
Instead the code fails with error: TypeError: not all arguments converted during string formatting. The error points to the line beginning with if a%2==0....
While researching this problem I found examples indicating that code like this should work. For example answers to this question offer similar code as solution: python - checking odd/even numbers and changing outputs on number size
So what is wrong with my code?
It's because you first test if a can be converted to an int (which is fine), but then you ignore this test and keep going with the string you provided in argument.
Python is a dynamically typed language, but also strongly typed, which means you can change the type of a variable after it's been declared, but this change has to be explicit (more about this here).
In your case, it means you can't do if a % 2 == 0 if a is a string.
You could do this for instance:
def oddoreven(a):
try:
my_int = int(a)
except TypeError:
return "The argument provided could not be converted into an int"
if my_int % 2 == 0:
return 1
else:
return 0
the int function doesn't change the a in-place, you need to assign it to a :
>>> def oddoreven(a):
... try: a=int(a)
... except: return "Error"
... if a%2==0: return 1
... else: return 0
...
>>> oddoreven('2')
1
>>> oddoreven('5')
0
>>> oddoreven('a')
'Error'
As user2357112 stated. (int)a does not convert a to a int. so when you check its modulus you still must convert it.
def oddoreven(a):
try: int(a)
except: return "Error"
if int(a)%2==0: return 1
else: return 0
print oddoreven(32)
works fine.
As a side note, catching any exception is generally frowned upon. You may want to narrow it down like:
def oddoreven(a):
try: int(a)
except TypeError: return "Error"
if int(a)%2==0: return 1
else: return 0
print oddoreven(32)