python Decimal - checking if integer - python

I am using the Decimal library in Python, and printing out the values using
format(value, 'f'), where value is a Decimal. I get numbers in the form 10.00000, which reflects the precision on the decimal. I know that float supports is_integer, but there seems to be a lack of a similar API for decimals. I was wondering if there was a way around this.

You could use the modulo operation to check if there is a non-integer remainder:
>>> from decimal import Decimal
>>> Decimal('3.14') % 1 == 0
False
>>> Decimal('3') % 1 == 0
True
>>> Decimal('3.0') % 1 == 0
True

Try math.floor(val) == val or val == int(val).

As of Python 3.6, Decimal has a method as_integer_ratio().
as_integer_ratio() returns a (numerator, denominator) tuple. If the denominator is 1, then the value is an integer.
>>> from decimal import Decimal
>>> Decimal("123.456").as_integer_ratio()[1] == 1
False
>>> Decimal("123.000").as_integer_ratio()[1] == 1
True

The mathematical solution is to convert your decimal number to integer and then test its equality with your number.
Since Decimal can have an arbitrary precision, you should not convert it to int or float.
Fortunately, the Decimalclass has a to_integral_value which make the conversion for you. You can adopt a solution like this:
def is_integer(d):
return d == d.to_integral_value()
Example:
from decimal import Decimal
d_int = Decimal(3)
assert is_integer(d_int)
d_float = Decimal(3.1415)
assert not is_integer(d_float)

Decimal does have a "hidden" method called _isinteger() that works kind of the like the float's is_integer() method:
>>> Decimal(1)._isinteger()
True
>>> Decimal(1.1)._isinteger()
Traceback (most recent call last):
File "C:\Program Files (x86)\Wing IDE 4.1\src\debug\tserver\_sandbox.py", line 1, in <module>
# Used internally for debug sandbox under external interpreter
File "C:\Python26\Lib\decimal.py", line 649, in __new__
"First convert the float to a string")
TypeError: Cannot convert float to Decimal. First convert the float to a string
As you can see, you would have to catch an exception though. Alternatively, you could do the test on the value BEFORE you pass it to Decimal using the float's method as you mentioned or by using isinstance.

You can call as_tuple() on a Decimal object to get the sign, the sequence of digits, and the exponent which together define the Decimal value.
If the exponent of a normalized Decimal is non-negative, then your value doesn't have a fractional component, i.e., it is an integer. So you can check for this very easily:
def is_integer(dec):
"""True if the given Decimal value is an integer, False otherwise."""
return dec.normalize().as_tuple()[2] >= 0
Try it and see:
from decimal import Decimal
decimals = [
Decimal('0'),
Decimal('0.0000'),
Decimal('1'),
Decimal('-1'),
Decimal('1000000'),
Decimal('0.1'),
Decimal('-0.0000000009'),
Decimal('32.4')]
for d in decimals:
print("Is {} an integer? {}".format(d, is_integer(d)))
Is 0 an integer? True
Is 0.0000 an integer? True
Is 1 an integer? True
Is -1 an integer? True
Is 1000000 an integer? True
Is 0.1 an integer? False
Is -9E-10 an integer? False
Is 32.4 an integer? False

Building on what was said above, I used:
>>> not 2.5 % 1
False
>>> not 1.0 % 1
True
>>> not 14.000001 % 1
False
>>> not 2.00000000 % 1
True
So you can use the following one liner:
not value % 1
It will provide you with your desired bool.

Decimal class has a function to_integral_exact which converts decimal to an integer and also signals if there were any non-zero digits discarded.
https://docs.python.org/3/library/decimal.html#decimal.Decimal.to_integral_exact
Using this information we can implment float's is_integer for Decimal too:
import decimal
def is_integer(value: decimal.Decimal) -> bool:
is_it = True
context = decimal.getcontext()
context.clear_flags()
exact = value.to_integral_exact()
if context.flags[decimal.Inexact]:
is_it = False
context.clear_flags()
return is_it
Using the function above:
# tested on Python 3.9
>>> is_integer(decimal.Decimal("0.23"))
False
>>> is_integer(decimal.Decimal("5.0000"))
True
>>> is_integer(decimal.Decimal("5.0001"))
False

Yet another way to do it is to use the quantize() method which is generally used to round decimals:
>>> from decimal import Decimal
>>> for d in (Decimal('2.72'), Decimal('3.14'), Decimal('3.0'), Decimal('3')):
... d == d.quantize(Decimal('1'))
...
False
False
True
True

Related

call different functions for list elements [duplicate]

How can I convert a str to float?
"545.2222" → 545.2222
How can I convert a str to int?
"31" → 31
For the reverse, see Convert integer to string in Python and Converting a float to a string without rounding it.
Please instead use How can I read inputs as numbers? to close duplicate questions where OP received a string from user input and immediately wants to convert it, or was hoping for input (in 3.x) to convert the type automatically.
>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545
Python2 method to check if a string is a float:
def is_float(value):
if value is None:
return False
try:
float(value)
return True
except:
return False
For the Python3 version of is_float see: Checking if a string can be converted to float in Python
A longer and more accurate name for this function could be: is_convertible_to_float(value)
What is, and is not a float in Python may surprise you:
The below unit tests were done using python2. Check it that Python3 has different behavior for what strings are convertable to float. One confounding difference is that any number of interior underscores are now allowed: (float("1_3.4") == float(13.4)) is True
val is_float(val) Note
-------------------- ---------- --------------------------------
"" False Blank string
"127" True Passed string
True True Pure sweet Truth
"True" False Vile contemptible lie
False True So false it becomes true
"123.456" True Decimal
" -127 " True Spaces trimmed
"\t\n12\r\n" True whitespace ignored
"NaN" True Not a number
"NaNanananaBATMAN" False I am Batman
"-iNF" True Negative infinity
"123.E4" True Exponential notation
".1" True mantissa only
"1_2_3.4" False Underscores not allowed
"12 34" False Spaces not allowed on interior
"1,234" False Commas gtfo
u'\x30' True Unicode is fine.
"NULL" False Null is not special
0x3fade True Hexadecimal
"6e7777777777777" True Shrunk to infinity
"1.797693e+308" True This is max value
"infinity" True Same as inf
"infinityandBEYOND" False Extra characters wreck it
"12.34.56" False Only one dot allowed
u'四' False Japanese '4' is not a float.
"#56" False Pound sign
"56%" False Percent of what?
"0E0" True Exponential, move dot 0 places
0**0 True 0___0 Exponentiation
"-5e-5" True Raise to a negative number
"+1e1" True Plus is OK with exponent
"+1e1^5" False Fancy exponent not interpreted
"+1e1.3" False No decimals in exponent
"-+1" False Make up your mind
"(1)" False Parenthesis is bad
You think you know what numbers are? You are not so good as you think! Not big surprise.
Don't use this code on life-critical software!
Catching broad exceptions this way, killing canaries and gobbling the exception creates a tiny chance that a valid float as string will return false. The float(...) line of code can failed for any of a thousand reasons that have nothing to do with the contents of the string. But if you're writing life-critical software in a duck-typing prototype language like Python, then you've got much larger problems.
def num(s):
try:
return int(s)
except ValueError:
return float(s)
This is another method which deserves to be mentioned here, ast.literal_eval:
This can be used for safely evaluating strings containing Python expressions from untrusted sources without the need to parse the values oneself.
That is, a safe 'eval'
>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31
Localization and commas
You should consider the possibility of commas in the string representation of a number, for cases like float("545,545.2222") which throws an exception. Instead, use methods in locale to convert the strings to numbers and interpret commas correctly. The locale.atof method converts to a float in one step once the locale has been set for the desired number convention.
Example 1 -- United States number conventions
In the United States and the UK, commas can be used as a thousands separator. In this example with American locale, the comma is handled properly as a separator:
>>> import locale
>>> a = u'545,545.2222'
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
'en_US.UTF-8'
>>> locale.atof(a)
545545.2222
>>> int(locale.atof(a))
545545
>>>
Example 2 -- European number conventions
In the majority of countries of the world, commas are used for decimal marks instead of periods. In this example with French locale, the comma is correctly handled as a decimal mark:
>>> import locale
>>> b = u'545,2222'
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.atof(b)
545.2222
The method locale.atoi is also available, but the argument should be an integer.
float(x) if '.' in x else int(x)
If you aren't averse to third-party modules, you could check out the fastnumbers module. It provides a function called fast_real that does exactly what this question is asking for and does it faster than a pure-Python implementation:
>>> from fastnumbers import fast_real
>>> fast_real("545.2222")
545.2222
>>> type(fast_real("545.2222"))
float
>>> fast_real("31")
31
>>> type(fast_real("31"))
int
Users codelogic and harley are correct, but keep in mind if you know the string is an integer (for example, 545) you can call int("545") without first casting to float.
If your strings are in a list, you could use the map function as well.
>>> x = ["545.0", "545.6", "999.2"]
>>> map(float, x)
[545.0, 545.60000000000002, 999.20000000000005]
>>>
It is only good if they're all the same type.
In Python, how can I parse a numeric string like "545.2222" to its corresponding float value, 542.2222? Or parse the string "31" to an integer, 31?
I just want to know how to parse a float string to a float, and (separately) an int string to an int.
It's good that you ask to do these separately. If you're mixing them, you may be setting yourself up for problems later. The simple answer is:
"545.2222" to float:
>>> float("545.2222")
545.2222
"31" to an integer:
>>> int("31")
31
Other conversions, ints to and from strings and literals:
Conversions from various bases, and you should know the base in advance (10 is the default). Note you can prefix them with what Python expects for its literals (see below) or remove the prefix:
>>> int("0b11111", 2)
31
>>> int("11111", 2)
31
>>> int('0o37', 8)
31
>>> int('37', 8)
31
>>> int('0x1f', 16)
31
>>> int('1f', 16)
31
If you don't know the base in advance, but you do know they will have the correct prefix, Python can infer this for you if you pass 0 as the base:
>>> int("0b11111", 0)
31
>>> int('0o37', 0)
31
>>> int('0x1f', 0)
31
Non-Decimal (i.e. Integer) Literals from other Bases
If your motivation is to have your own code clearly represent hard-coded specific values, however, you may not need to convert from the bases - you can let Python do it for you automatically with the correct syntax.
You can use the apropos prefixes to get automatic conversion to integers with the following literals. These are valid for Python 2 and 3:
Binary, prefix 0b
>>> 0b11111
31
Octal, prefix 0o
>>> 0o37
31
Hexadecimal, prefix 0x
>>> 0x1f
31
This can be useful when describing binary flags, file permissions in code, or hex values for colors - for example, note no quotes:
>>> 0b10101 # binary flags
21
>>> 0o755 # read, write, execute perms for owner, read & ex for group & others
493
>>> 0xffffff # the color, white, max values for red, green, and blue
16777215
Making ambiguous Python 2 octals compatible with Python 3
If you see an integer that starts with a 0, in Python 2, this is (deprecated) octal syntax.
>>> 037
31
It is bad because it looks like the value should be 37. So in Python 3, it now raises a SyntaxError:
>>> 037
File "<stdin>", line 1
037
^
SyntaxError: invalid token
Convert your Python 2 octals to octals that work in both 2 and 3 with the 0o prefix:
>>> 0o37
31
The question seems a little bit old. But let me suggest a function, parseStr, which makes something similar, that is, returns integer or float and if a given ASCII string cannot be converted to none of them it returns it untouched. The code of course might be adjusted to do only what you want:
>>> import string
>>> parseStr = lambda x: x.isalpha() and x or x.isdigit() and \
... int(x) or x.isalnum() and x or \
... len(set(string.punctuation).intersection(x)) == 1 and \
... x.count('.') == 1 and float(x) or x
>>> parseStr('123')
123
>>> parseStr('123.3')
123.3
>>> parseStr('3HC1')
'3HC1'
>>> parseStr('12.e5')
1200000.0
>>> parseStr('12$5')
'12$5'
>>> parseStr('12.2.2')
'12.2.2'
float("545.2222") and int(float("545.2222"))
The YAML parser can help you figure out what datatype your string is. Use yaml.load(), and then you can use type(result) to test for type:
>>> import yaml
>>> a = "545.2222"
>>> result = yaml.load(a)
>>> result
545.22220000000004
>>> type(result)
<type 'float'>
>>> b = "31"
>>> result = yaml.load(b)
>>> result
31
>>> type(result)
<type 'int'>
>>> c = "HI"
>>> result = yaml.load(c)
>>> result
'HI'
>>> type(result)
<type 'str'>
I use this function for that
import ast
def parse_str(s):
try:
return ast.literal_eval(str(s))
except:
return
It will convert the string to its type
value = parse_str('1') # Returns Integer
value = parse_str('1.5') # Returns Float
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else number_as_float
def num(s):
"""num(s)
num(3),num(3.7)-->3
num('3')-->3, num('3.7')-->3.7
num('3,700')-->ValueError
num('3a'),num('a3'),-->ValueError
num('3e4') --> 30000.0
"""
try:
return int(s)
except ValueError:
try:
return float(s)
except ValueError:
raise ValueError('argument is not a string of number')
You could use json.loads:
>>> import json
>>> json.loads('123.456')
123.456
>>> type(_)
<class 'float'>
>>>
As you can see it becomes a type of float.
You need to take into account rounding to do this properly.
i.e. - int(5.1) => 5
int(5.6) => 5 -- wrong, should be 6 so we do int(5.6 + 0.5) => 6
def convert(n):
try:
return int(n)
except ValueError:
return float(n + 0.5)
To typecast in Python use the constructor functions of the type, passing the string (or whatever value you are trying to cast) as a parameter.
For example:
>>>float("23.333")
23.333
Behind the scenes, Python is calling the objects __float__ method, which should return a float representation of the parameter. This is especially powerful, as you can define your own types (using classes) with a __float__ method so that it can be casted into a float using float(myobject).
Handles hex, octal, binary, decimal, and float
This solution will handle all of the string conventions for numbers (all that I know about).
def to_number(n):
''' Convert any number representation to a number
This covers: float, decimal, hex, and octal numbers.
'''
try:
return int(str(n), 0)
except:
try:
# Python 3 doesn't accept "010" as a valid octal. You must use the
# '0o' prefix
return int('0o' + n, 0)
except:
return float(n)
This test case output illustrates what I'm talking about.
======================== CAPTURED OUTPUT =========================
to_number(3735928559) = 3735928559 == 3735928559
to_number("0xFEEDFACE") = 4277009102 == 4277009102
to_number("0x0") = 0 == 0
to_number(100) = 100 == 100
to_number("42") = 42 == 42
to_number(8) = 8 == 8
to_number("0o20") = 16 == 16
to_number("020") = 16 == 16
to_number(3.14) = 3.14 == 3.14
to_number("2.72") = 2.72 == 2.72
to_number("1e3") = 1000.0 == 1000
to_number(0.001) = 0.001 == 0.001
to_number("0xA") = 10 == 10
to_number("012") = 10 == 10
to_number("0o12") = 10 == 10
to_number("0b01010") = 10 == 10
to_number("10") = 10 == 10
to_number("10.0") = 10.0 == 10
to_number("1e1") = 10.0 == 10
Here is the test:
class test_to_number(unittest.TestCase):
def test_hex(self):
# All of the following should be converted to an integer
#
values = [
# HEX
# ----------------------
# Input | Expected
# ----------------------
(0xDEADBEEF , 3735928559), # Hex
("0xFEEDFACE", 4277009102), # Hex
("0x0" , 0), # Hex
# Decimals
# ----------------------
# Input | Expected
# ----------------------
(100 , 100), # Decimal
("42" , 42), # Decimal
]
values += [
# Octals
# ----------------------
# Input | Expected
# ----------------------
(0o10 , 8), # Octal
("0o20" , 16), # Octal
("020" , 16), # Octal
]
values += [
# Floats
# ----------------------
# Input | Expected
# ----------------------
(3.14 , 3.14), # Float
("2.72" , 2.72), # Float
("1e3" , 1000), # Float
(1e-3 , 0.001), # Float
]
values += [
# All ints
# ----------------------
# Input | Expected
# ----------------------
("0xA" , 10),
("012" , 10),
("0o12" , 10),
("0b01010" , 10),
("10" , 10),
("10.0" , 10),
("1e1" , 10),
]
for _input, expected in values:
value = to_number(_input)
if isinstance(_input, str):
cmd = 'to_number("{}")'.format(_input)
else:
cmd = 'to_number({})'.format(_input)
print("{:23} = {:10} == {:10}".format(cmd, value, expected))
self.assertEqual(value, expected)
Pass your string to this function:
def string_to_number(str):
if("." in str):
try:
res = float(str)
except:
res = str
elif(str.isdigit()):
res = int(str)
else:
res = str
return(res)
It will return int, float or string depending on what was passed.
String that is an int
print(type(string_to_number("124")))
<class 'int'>
String that is a float
print(type(string_to_number("12.4")))
<class 'float'>
String that is a string
print(type(string_to_number("hello")))
<class 'str'>
String that looks like a float
print(type(string_to_number("hel.lo")))
<class 'str'>
There is also regex, because sometimes string must be prepared and normalized before casting to a number:
import re
def parseNumber(value, as_int=False):
try:
number = float(re.sub('[^.\-\d]', '', value))
if as_int:
return int(number + 0.5)
else:
return number
except ValueError:
return float('nan') # or None if you wish
Usage:
parseNumber('13,345')
> 13345.0
parseNumber('- 123 000')
> -123000.0
parseNumber('99999\n')
> 99999.0
And by the way, something to verify you have a number:
import numbers
def is_number(value):
return isinstance(value, numbers.Number)
# Will work with int, float, long, Decimal
a = int(float(a)) if int(float(a)) == float(a) else float(a)
This is a corrected version of Totoro's answer.
This will try to parse a string and return either int or float depending on what the string represents. It might rise parsing exceptions or have some unexpected behaviour.
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else
number_as_float
If you are dealing with mixed integers and floats and want a consistent way to deal with your mixed data, here is my solution with the proper docstring:
def parse_num(candidate):
"""Parse string to number if possible
It work equally well with negative and positive numbers, integers and floats.
Args:
candidate (str): string to convert
Returns:
float | int | None: float or int if possible otherwise None
"""
try:
float_value = float(candidate)
except ValueError:
return None
# Optional part if you prefer int to float when decimal part is 0
if float_value.is_integer():
return int(float_value)
# end of the optional part
return float_value
# Test
candidates = ['34.77', '-13', 'jh', '8990', '76_3234_54']
res_list = list(map(parse_num, candidates))
print('Before:')
print(candidates)
print('After:')
print(res_list)
Output:
Before:
['34.77', '-13', 'jh', '8990', '76_3234_54']
After:
[34.77, -13, None, 8990, 76323454]
Use:
def num(s):
try:
for each in s:
yield int(each)
except ValueError:
yield float(each)
a = num(["123.55","345","44"])
print a.next()
print a.next()
This is the most Pythonic way I could come up with.
If you don't want to use third party modules the following might be the most robust solution:
def string_to_int_or_float(s):
try:
f = float(s) # replace s with str(s) if you are not sure that s is a string
except ValueError:
print("Provided string '" + s + "' is not interpretable as a literal number.")
raise
try:
i = int(str(f).rstrip('0').rstrip('.'))
except:
return f
return i
It might not be the fastest, but it handles correctly literal numbers where many other solutions fail, such as:
>>> string_to_int_or_float('789.')
789
>>> string_to_int_or_float('789.0')
789
>>> string_to_int_or_float('12.3e2')
1230
>>> string_to_int_or_float('12.3e-2')
0.123
>>> string_to_int_or_float('4560e-1')
456
>>> string_to_int_or_float('4560e-2')
45.6
You can simply do this by
s = '542.22'
f = float(s) # This converts string data to float data with a decimal point
print(f)
i = int(f) # This converts string data to integer data by just taking the whole number part of it
print(i)
For more information on parsing of data types check on python documentation!
This is a function which will convert any object (not just str) to int or float, based on if the actual string supplied looks like int or float. Further if it's an object which has both __float and __int__ methods, it defaults to using __float__
def conv_to_num(x, num_type='asis'):
'''Converts an object to a number if possible.
num_type: int, float, 'asis'
Defaults to floating point in case of ambiguity.
'''
import numbers
is_num, is_str, is_other = [False]*3
if isinstance(x, numbers.Number):
is_num = True
elif isinstance(x, str):
is_str = True
is_other = not any([is_num, is_str])
if is_num:
res = x
elif is_str:
is_float, is_int, is_char = [False]*3
try:
res = float(x)
if '.' in x:
is_float = True
else:
is_int = True
except ValueError:
res = x
is_char = True
else:
if num_type == 'asis':
funcs = [int, float]
else:
funcs = [num_type]
for func in funcs:
try:
res = func(x)
break
except TypeError:
continue
else:
res = x
By using int and float methods we can convert a string to integer and floats.
s="45.8"
print(float(s))
y='67'
print(int(y))
For numbers and characters together:
string_for_int = "498 results should get"
string_for_float = "498.45645765 results should get"
First import re:
import re
# For getting the integer part:
print(int(re.search(r'\d+', string_for_int).group())) #498
# For getting the float part:
print(float(re.search(r'\d+\.\d+', string_for_float).group())) #498.45645765
For easy model:
value1 = "10"
value2 = "10.2"
print(int(value1)) # 10
print(float(value2)) # 10.2

Best way to see if a number is fractional or not

I'm looking to differentiate between a number like
2.0 or 2 and an actual fractional number such as 2.4. What would be the best way to do this? Currently I'm doing:
def is_fractional(num):
if not str(num).replace('.','').isdigit(): return
return float(num) != int(num)
>>> is_fractional(2)
False
>>> is_fractional(2.1)
True
>>> is_fractional(2.0)
False
>>> is_fractional('a')
>>>
That operation is built-in:
>>> 5.0.is_integer()
True
>>> 5.00000001.is_integer()
False
>>> 4.9999999.is_integer()
False
Documentation is here.
ADDENDUM
The initial solution only works for float. Here's a more complete answer, with tests:
from decimal import Decimal
def is_integer(x):
if isinstance(x, int):
return True
elif isinstance(x, float):
return x.is_integer()
elif isinstance(x, Decimal):
return x.as_integer_ratio()[1] == 1
return False
good = [
0,
0.0,
3,
-9999999999999999999999,
-2.0000000000000,
Decimal("3.000000"),
Decimal("-9")
]
bad = [
-9.99999999999999,
"dogs",
Decimal("-4.00000000000000000000000000000000001"),
Decimal("0.99999999999999999999999999999999999")
]
for x in good:
assert is_integer(x)
for x in bad:
assert not is_integer(x)
print("All tests passed")
If some of your numbers are decimal.Decimals, they might have range issues where conversion to float fails, or drops the fractional part that actually exists, depending on their precision:
>>> import decimal
>>> x = decimal.Decimal('1.00000000000000000000000000000000000001')
>>> str(x)
'1.00000000000000000000000000000000000001'
>>> float(x).is_integer()
True
>>> y = decimal.Decimal('1e5000')
>>> str(y)
'1E+5000'
>>> float(y)
inf
The str method will generally work (modulo problem cases like the one illustrated above), so you could stick with that, but it might be better to attempt to use is_integer and use a fallback if that fails:
try:
return x.is_integer()
except AttributeError:
pass
(as others note, you'll need to check for int and long here as well, if those are allowed types, since they are integers by definition but lack an is_integer attribute).
At this point, it's worth considering all of the other answers, but here's a specific decimal.Decimal handler:
# optional: special case decimal.Decimal here
try:
as_tuple = x.as_tuple()
trailing0s = len(list(itertools.takewhile(lambda i: i == 0, reversed(as_tuple[1]))))
return as_tuple[2] + trailing0s < 0
except (AttributeError, IndexError): # no as_tuple, or not 3 elements long, etc
pass
Why do not check if the difference between the truncation to integer and the exact value is not zero?
is_frac = lambda x: int(x)-x != 0
Python includes a fractions module that generates fractions (rational numbers) from strings, floats, integers, and much more. Just create a Fraction and check whether its denominator is other than 1 (the Fraction constructor will automatically reduce the number to lowest terms):
from fractions import Fraction
def is_fractional(num):
return Fraction(num).denominator != 1
Note that the method above may raise an exception if the conversion to a Fraction fails. In this case, it's not known whether the object is fractional.
If you are dealing with decimal module or with a float object, you can do this easily:
def is_factional(num):
return isinstance(num, (float, Decimal))
Here is one way to do it (assuming e.g. 2/2 is not "fractional" in the sense you have in mind):
# could also extend to other numeric types numpy.float32
from decimal import Decimal
def is_frac(n):
numeric_types = (int, float, Decimal)
assert isinstance(n, numeric_types), 'n must be numeric :/'
# (ints are never fractions)
if type(n) is int: return False
return n != float(int(n))
# various sorts of numbers
ns = [-1, -1.0, 0, 0.1, 1, 1.0, 1., 2.3, 1e0, 1e3, 1.1e3,
Decimal(3), Decimal(3.0), Decimal(3.1)]
# confirm that values are as expected
dict(zip(ns, [is_frac(n) for n in ns]))
This will only work if n is an int or a float or decimal.Decimal. But you could extend it to handle other numeric types such as numpy.float64 or numpy.int32 by just including them in numeric_types.

How to display decimals python 3.6.0 [duplicate]

How can I convert a str to float?
"545.2222" → 545.2222
How can I convert a str to int?
"31" → 31
For the reverse, see Convert integer to string in Python and Converting a float to a string without rounding it.
Please instead use How can I read inputs as numbers? to close duplicate questions where OP received a string from user input and immediately wants to convert it, or was hoping for input (in 3.x) to convert the type automatically.
>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545
Python2 method to check if a string is a float:
def is_float(value):
if value is None:
return False
try:
float(value)
return True
except:
return False
For the Python3 version of is_float see: Checking if a string can be converted to float in Python
A longer and more accurate name for this function could be: is_convertible_to_float(value)
What is, and is not a float in Python may surprise you:
The below unit tests were done using python2. Check it that Python3 has different behavior for what strings are convertable to float. One confounding difference is that any number of interior underscores are now allowed: (float("1_3.4") == float(13.4)) is True
val is_float(val) Note
-------------------- ---------- --------------------------------
"" False Blank string
"127" True Passed string
True True Pure sweet Truth
"True" False Vile contemptible lie
False True So false it becomes true
"123.456" True Decimal
" -127 " True Spaces trimmed
"\t\n12\r\n" True whitespace ignored
"NaN" True Not a number
"NaNanananaBATMAN" False I am Batman
"-iNF" True Negative infinity
"123.E4" True Exponential notation
".1" True mantissa only
"1_2_3.4" False Underscores not allowed
"12 34" False Spaces not allowed on interior
"1,234" False Commas gtfo
u'\x30' True Unicode is fine.
"NULL" False Null is not special
0x3fade True Hexadecimal
"6e7777777777777" True Shrunk to infinity
"1.797693e+308" True This is max value
"infinity" True Same as inf
"infinityandBEYOND" False Extra characters wreck it
"12.34.56" False Only one dot allowed
u'四' False Japanese '4' is not a float.
"#56" False Pound sign
"56%" False Percent of what?
"0E0" True Exponential, move dot 0 places
0**0 True 0___0 Exponentiation
"-5e-5" True Raise to a negative number
"+1e1" True Plus is OK with exponent
"+1e1^5" False Fancy exponent not interpreted
"+1e1.3" False No decimals in exponent
"-+1" False Make up your mind
"(1)" False Parenthesis is bad
You think you know what numbers are? You are not so good as you think! Not big surprise.
Don't use this code on life-critical software!
Catching broad exceptions this way, killing canaries and gobbling the exception creates a tiny chance that a valid float as string will return false. The float(...) line of code can failed for any of a thousand reasons that have nothing to do with the contents of the string. But if you're writing life-critical software in a duck-typing prototype language like Python, then you've got much larger problems.
def num(s):
try:
return int(s)
except ValueError:
return float(s)
This is another method which deserves to be mentioned here, ast.literal_eval:
This can be used for safely evaluating strings containing Python expressions from untrusted sources without the need to parse the values oneself.
That is, a safe 'eval'
>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31
Localization and commas
You should consider the possibility of commas in the string representation of a number, for cases like float("545,545.2222") which throws an exception. Instead, use methods in locale to convert the strings to numbers and interpret commas correctly. The locale.atof method converts to a float in one step once the locale has been set for the desired number convention.
Example 1 -- United States number conventions
In the United States and the UK, commas can be used as a thousands separator. In this example with American locale, the comma is handled properly as a separator:
>>> import locale
>>> a = u'545,545.2222'
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
'en_US.UTF-8'
>>> locale.atof(a)
545545.2222
>>> int(locale.atof(a))
545545
>>>
Example 2 -- European number conventions
In the majority of countries of the world, commas are used for decimal marks instead of periods. In this example with French locale, the comma is correctly handled as a decimal mark:
>>> import locale
>>> b = u'545,2222'
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.atof(b)
545.2222
The method locale.atoi is also available, but the argument should be an integer.
float(x) if '.' in x else int(x)
If you aren't averse to third-party modules, you could check out the fastnumbers module. It provides a function called fast_real that does exactly what this question is asking for and does it faster than a pure-Python implementation:
>>> from fastnumbers import fast_real
>>> fast_real("545.2222")
545.2222
>>> type(fast_real("545.2222"))
float
>>> fast_real("31")
31
>>> type(fast_real("31"))
int
Users codelogic and harley are correct, but keep in mind if you know the string is an integer (for example, 545) you can call int("545") without first casting to float.
If your strings are in a list, you could use the map function as well.
>>> x = ["545.0", "545.6", "999.2"]
>>> map(float, x)
[545.0, 545.60000000000002, 999.20000000000005]
>>>
It is only good if they're all the same type.
In Python, how can I parse a numeric string like "545.2222" to its corresponding float value, 542.2222? Or parse the string "31" to an integer, 31?
I just want to know how to parse a float string to a float, and (separately) an int string to an int.
It's good that you ask to do these separately. If you're mixing them, you may be setting yourself up for problems later. The simple answer is:
"545.2222" to float:
>>> float("545.2222")
545.2222
"31" to an integer:
>>> int("31")
31
Other conversions, ints to and from strings and literals:
Conversions from various bases, and you should know the base in advance (10 is the default). Note you can prefix them with what Python expects for its literals (see below) or remove the prefix:
>>> int("0b11111", 2)
31
>>> int("11111", 2)
31
>>> int('0o37', 8)
31
>>> int('37', 8)
31
>>> int('0x1f', 16)
31
>>> int('1f', 16)
31
If you don't know the base in advance, but you do know they will have the correct prefix, Python can infer this for you if you pass 0 as the base:
>>> int("0b11111", 0)
31
>>> int('0o37', 0)
31
>>> int('0x1f', 0)
31
Non-Decimal (i.e. Integer) Literals from other Bases
If your motivation is to have your own code clearly represent hard-coded specific values, however, you may not need to convert from the bases - you can let Python do it for you automatically with the correct syntax.
You can use the apropos prefixes to get automatic conversion to integers with the following literals. These are valid for Python 2 and 3:
Binary, prefix 0b
>>> 0b11111
31
Octal, prefix 0o
>>> 0o37
31
Hexadecimal, prefix 0x
>>> 0x1f
31
This can be useful when describing binary flags, file permissions in code, or hex values for colors - for example, note no quotes:
>>> 0b10101 # binary flags
21
>>> 0o755 # read, write, execute perms for owner, read & ex for group & others
493
>>> 0xffffff # the color, white, max values for red, green, and blue
16777215
Making ambiguous Python 2 octals compatible with Python 3
If you see an integer that starts with a 0, in Python 2, this is (deprecated) octal syntax.
>>> 037
31
It is bad because it looks like the value should be 37. So in Python 3, it now raises a SyntaxError:
>>> 037
File "<stdin>", line 1
037
^
SyntaxError: invalid token
Convert your Python 2 octals to octals that work in both 2 and 3 with the 0o prefix:
>>> 0o37
31
The question seems a little bit old. But let me suggest a function, parseStr, which makes something similar, that is, returns integer or float and if a given ASCII string cannot be converted to none of them it returns it untouched. The code of course might be adjusted to do only what you want:
>>> import string
>>> parseStr = lambda x: x.isalpha() and x or x.isdigit() and \
... int(x) or x.isalnum() and x or \
... len(set(string.punctuation).intersection(x)) == 1 and \
... x.count('.') == 1 and float(x) or x
>>> parseStr('123')
123
>>> parseStr('123.3')
123.3
>>> parseStr('3HC1')
'3HC1'
>>> parseStr('12.e5')
1200000.0
>>> parseStr('12$5')
'12$5'
>>> parseStr('12.2.2')
'12.2.2'
float("545.2222") and int(float("545.2222"))
The YAML parser can help you figure out what datatype your string is. Use yaml.load(), and then you can use type(result) to test for type:
>>> import yaml
>>> a = "545.2222"
>>> result = yaml.load(a)
>>> result
545.22220000000004
>>> type(result)
<type 'float'>
>>> b = "31"
>>> result = yaml.load(b)
>>> result
31
>>> type(result)
<type 'int'>
>>> c = "HI"
>>> result = yaml.load(c)
>>> result
'HI'
>>> type(result)
<type 'str'>
I use this function for that
import ast
def parse_str(s):
try:
return ast.literal_eval(str(s))
except:
return
It will convert the string to its type
value = parse_str('1') # Returns Integer
value = parse_str('1.5') # Returns Float
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else number_as_float
def num(s):
"""num(s)
num(3),num(3.7)-->3
num('3')-->3, num('3.7')-->3.7
num('3,700')-->ValueError
num('3a'),num('a3'),-->ValueError
num('3e4') --> 30000.0
"""
try:
return int(s)
except ValueError:
try:
return float(s)
except ValueError:
raise ValueError('argument is not a string of number')
You could use json.loads:
>>> import json
>>> json.loads('123.456')
123.456
>>> type(_)
<class 'float'>
>>>
As you can see it becomes a type of float.
You need to take into account rounding to do this properly.
i.e. - int(5.1) => 5
int(5.6) => 5 -- wrong, should be 6 so we do int(5.6 + 0.5) => 6
def convert(n):
try:
return int(n)
except ValueError:
return float(n + 0.5)
To typecast in Python use the constructor functions of the type, passing the string (or whatever value you are trying to cast) as a parameter.
For example:
>>>float("23.333")
23.333
Behind the scenes, Python is calling the objects __float__ method, which should return a float representation of the parameter. This is especially powerful, as you can define your own types (using classes) with a __float__ method so that it can be casted into a float using float(myobject).
Handles hex, octal, binary, decimal, and float
This solution will handle all of the string conventions for numbers (all that I know about).
def to_number(n):
''' Convert any number representation to a number
This covers: float, decimal, hex, and octal numbers.
'''
try:
return int(str(n), 0)
except:
try:
# Python 3 doesn't accept "010" as a valid octal. You must use the
# '0o' prefix
return int('0o' + n, 0)
except:
return float(n)
This test case output illustrates what I'm talking about.
======================== CAPTURED OUTPUT =========================
to_number(3735928559) = 3735928559 == 3735928559
to_number("0xFEEDFACE") = 4277009102 == 4277009102
to_number("0x0") = 0 == 0
to_number(100) = 100 == 100
to_number("42") = 42 == 42
to_number(8) = 8 == 8
to_number("0o20") = 16 == 16
to_number("020") = 16 == 16
to_number(3.14) = 3.14 == 3.14
to_number("2.72") = 2.72 == 2.72
to_number("1e3") = 1000.0 == 1000
to_number(0.001) = 0.001 == 0.001
to_number("0xA") = 10 == 10
to_number("012") = 10 == 10
to_number("0o12") = 10 == 10
to_number("0b01010") = 10 == 10
to_number("10") = 10 == 10
to_number("10.0") = 10.0 == 10
to_number("1e1") = 10.0 == 10
Here is the test:
class test_to_number(unittest.TestCase):
def test_hex(self):
# All of the following should be converted to an integer
#
values = [
# HEX
# ----------------------
# Input | Expected
# ----------------------
(0xDEADBEEF , 3735928559), # Hex
("0xFEEDFACE", 4277009102), # Hex
("0x0" , 0), # Hex
# Decimals
# ----------------------
# Input | Expected
# ----------------------
(100 , 100), # Decimal
("42" , 42), # Decimal
]
values += [
# Octals
# ----------------------
# Input | Expected
# ----------------------
(0o10 , 8), # Octal
("0o20" , 16), # Octal
("020" , 16), # Octal
]
values += [
# Floats
# ----------------------
# Input | Expected
# ----------------------
(3.14 , 3.14), # Float
("2.72" , 2.72), # Float
("1e3" , 1000), # Float
(1e-3 , 0.001), # Float
]
values += [
# All ints
# ----------------------
# Input | Expected
# ----------------------
("0xA" , 10),
("012" , 10),
("0o12" , 10),
("0b01010" , 10),
("10" , 10),
("10.0" , 10),
("1e1" , 10),
]
for _input, expected in values:
value = to_number(_input)
if isinstance(_input, str):
cmd = 'to_number("{}")'.format(_input)
else:
cmd = 'to_number({})'.format(_input)
print("{:23} = {:10} == {:10}".format(cmd, value, expected))
self.assertEqual(value, expected)
Pass your string to this function:
def string_to_number(str):
if("." in str):
try:
res = float(str)
except:
res = str
elif(str.isdigit()):
res = int(str)
else:
res = str
return(res)
It will return int, float or string depending on what was passed.
String that is an int
print(type(string_to_number("124")))
<class 'int'>
String that is a float
print(type(string_to_number("12.4")))
<class 'float'>
String that is a string
print(type(string_to_number("hello")))
<class 'str'>
String that looks like a float
print(type(string_to_number("hel.lo")))
<class 'str'>
There is also regex, because sometimes string must be prepared and normalized before casting to a number:
import re
def parseNumber(value, as_int=False):
try:
number = float(re.sub('[^.\-\d]', '', value))
if as_int:
return int(number + 0.5)
else:
return number
except ValueError:
return float('nan') # or None if you wish
Usage:
parseNumber('13,345')
> 13345.0
parseNumber('- 123 000')
> -123000.0
parseNumber('99999\n')
> 99999.0
And by the way, something to verify you have a number:
import numbers
def is_number(value):
return isinstance(value, numbers.Number)
# Will work with int, float, long, Decimal
a = int(float(a)) if int(float(a)) == float(a) else float(a)
This is a corrected version of Totoro's answer.
This will try to parse a string and return either int or float depending on what the string represents. It might rise parsing exceptions or have some unexpected behaviour.
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else
number_as_float
If you are dealing with mixed integers and floats and want a consistent way to deal with your mixed data, here is my solution with the proper docstring:
def parse_num(candidate):
"""Parse string to number if possible
It work equally well with negative and positive numbers, integers and floats.
Args:
candidate (str): string to convert
Returns:
float | int | None: float or int if possible otherwise None
"""
try:
float_value = float(candidate)
except ValueError:
return None
# Optional part if you prefer int to float when decimal part is 0
if float_value.is_integer():
return int(float_value)
# end of the optional part
return float_value
# Test
candidates = ['34.77', '-13', 'jh', '8990', '76_3234_54']
res_list = list(map(parse_num, candidates))
print('Before:')
print(candidates)
print('After:')
print(res_list)
Output:
Before:
['34.77', '-13', 'jh', '8990', '76_3234_54']
After:
[34.77, -13, None, 8990, 76323454]
Use:
def num(s):
try:
for each in s:
yield int(each)
except ValueError:
yield float(each)
a = num(["123.55","345","44"])
print a.next()
print a.next()
This is the most Pythonic way I could come up with.
If you don't want to use third party modules the following might be the most robust solution:
def string_to_int_or_float(s):
try:
f = float(s) # replace s with str(s) if you are not sure that s is a string
except ValueError:
print("Provided string '" + s + "' is not interpretable as a literal number.")
raise
try:
i = int(str(f).rstrip('0').rstrip('.'))
except:
return f
return i
It might not be the fastest, but it handles correctly literal numbers where many other solutions fail, such as:
>>> string_to_int_or_float('789.')
789
>>> string_to_int_or_float('789.0')
789
>>> string_to_int_or_float('12.3e2')
1230
>>> string_to_int_or_float('12.3e-2')
0.123
>>> string_to_int_or_float('4560e-1')
456
>>> string_to_int_or_float('4560e-2')
45.6
You can simply do this by
s = '542.22'
f = float(s) # This converts string data to float data with a decimal point
print(f)
i = int(f) # This converts string data to integer data by just taking the whole number part of it
print(i)
For more information on parsing of data types check on python documentation!
This is a function which will convert any object (not just str) to int or float, based on if the actual string supplied looks like int or float. Further if it's an object which has both __float and __int__ methods, it defaults to using __float__
def conv_to_num(x, num_type='asis'):
'''Converts an object to a number if possible.
num_type: int, float, 'asis'
Defaults to floating point in case of ambiguity.
'''
import numbers
is_num, is_str, is_other = [False]*3
if isinstance(x, numbers.Number):
is_num = True
elif isinstance(x, str):
is_str = True
is_other = not any([is_num, is_str])
if is_num:
res = x
elif is_str:
is_float, is_int, is_char = [False]*3
try:
res = float(x)
if '.' in x:
is_float = True
else:
is_int = True
except ValueError:
res = x
is_char = True
else:
if num_type == 'asis':
funcs = [int, float]
else:
funcs = [num_type]
for func in funcs:
try:
res = func(x)
break
except TypeError:
continue
else:
res = x
By using int and float methods we can convert a string to integer and floats.
s="45.8"
print(float(s))
y='67'
print(int(y))
For numbers and characters together:
string_for_int = "498 results should get"
string_for_float = "498.45645765 results should get"
First import re:
import re
# For getting the integer part:
print(int(re.search(r'\d+', string_for_int).group())) #498
# For getting the float part:
print(float(re.search(r'\d+\.\d+', string_for_float).group())) #498.45645765
For easy model:
value1 = "10"
value2 = "10.2"
print(int(value1)) # 10
print(float(value2)) # 10.2

python unittest2 assertAlmostEqual with `places` works incorrectly

I am dealing with the following problem with unittest2:
assertAlmostEqual(69.88, 69.875, places=2) # returns True
but
assertAlmostEqual(1.28, 1.275, places=2) # returns False
I think problem is in the assertAlmostEqual method:
def assertAlmostEqual(self, first, second, places=None, ...):
if first == second:
# shortcut
return
...
if delta is not None:
...
else:
if places is None:
places = 7
if round(abs(second-first), places) == 0:
return
...
raise self.failureException(msg)
Should it instead be:
if abs(round(second, places) - round(first, places)) == 0
return
Your proposed fix doesn't make any difference, as you can easily demonstrate:
>>> places = 2
>>> first, second = 69.88, 69.875
>>> round(abs(second-first), places)
0.0
>>> abs(round(second, places) - round(first, places))
0.0
This is a problem with floating point precision, see e.g. Is floating point math broken? 69.88 cannot be represented exactly:
>>> "{:.40f}".format(69.88)
'69.8799999999999954525264911353588104248047'
The difference in the second example is
0.005
And even without mentioned biases of floating points result of round will be 0.01, so these numbers really different with 2-places precision
This method compares difference between numbers. It is kinda standard of comparing float numbers actually
So the problem is not with implementation, but with you expectations, that is different from common float comparison

How do I parse a string to a float or int?

How can I convert a str to float?
"545.2222" → 545.2222
How can I convert a str to int?
"31" → 31
For the reverse, see Convert integer to string in Python and Converting a float to a string without rounding it.
Please instead use How can I read inputs as numbers? to close duplicate questions where OP received a string from user input and immediately wants to convert it, or was hoping for input (in 3.x) to convert the type automatically.
>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545
Python2 method to check if a string is a float:
def is_float(value):
if value is None:
return False
try:
float(value)
return True
except:
return False
For the Python3 version of is_float see: Checking if a string can be converted to float in Python
A longer and more accurate name for this function could be: is_convertible_to_float(value)
What is, and is not a float in Python may surprise you:
The below unit tests were done using python2. Check it that Python3 has different behavior for what strings are convertable to float. One confounding difference is that any number of interior underscores are now allowed: (float("1_3.4") == float(13.4)) is True
val is_float(val) Note
-------------------- ---------- --------------------------------
"" False Blank string
"127" True Passed string
True True Pure sweet Truth
"True" False Vile contemptible lie
False True So false it becomes true
"123.456" True Decimal
" -127 " True Spaces trimmed
"\t\n12\r\n" True whitespace ignored
"NaN" True Not a number
"NaNanananaBATMAN" False I am Batman
"-iNF" True Negative infinity
"123.E4" True Exponential notation
".1" True mantissa only
"1_2_3.4" False Underscores not allowed
"12 34" False Spaces not allowed on interior
"1,234" False Commas gtfo
u'\x30' True Unicode is fine.
"NULL" False Null is not special
0x3fade True Hexadecimal
"6e7777777777777" True Shrunk to infinity
"1.797693e+308" True This is max value
"infinity" True Same as inf
"infinityandBEYOND" False Extra characters wreck it
"12.34.56" False Only one dot allowed
u'四' False Japanese '4' is not a float.
"#56" False Pound sign
"56%" False Percent of what?
"0E0" True Exponential, move dot 0 places
0**0 True 0___0 Exponentiation
"-5e-5" True Raise to a negative number
"+1e1" True Plus is OK with exponent
"+1e1^5" False Fancy exponent not interpreted
"+1e1.3" False No decimals in exponent
"-+1" False Make up your mind
"(1)" False Parenthesis is bad
You think you know what numbers are? You are not so good as you think! Not big surprise.
Don't use this code on life-critical software!
Catching broad exceptions this way, killing canaries and gobbling the exception creates a tiny chance that a valid float as string will return false. The float(...) line of code can failed for any of a thousand reasons that have nothing to do with the contents of the string. But if you're writing life-critical software in a duck-typing prototype language like Python, then you've got much larger problems.
def num(s):
try:
return int(s)
except ValueError:
return float(s)
This is another method which deserves to be mentioned here, ast.literal_eval:
This can be used for safely evaluating strings containing Python expressions from untrusted sources without the need to parse the values oneself.
That is, a safe 'eval'
>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31
Localization and commas
You should consider the possibility of commas in the string representation of a number, for cases like float("545,545.2222") which throws an exception. Instead, use methods in locale to convert the strings to numbers and interpret commas correctly. The locale.atof method converts to a float in one step once the locale has been set for the desired number convention.
Example 1 -- United States number conventions
In the United States and the UK, commas can be used as a thousands separator. In this example with American locale, the comma is handled properly as a separator:
>>> import locale
>>> a = u'545,545.2222'
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
'en_US.UTF-8'
>>> locale.atof(a)
545545.2222
>>> int(locale.atof(a))
545545
>>>
Example 2 -- European number conventions
In the majority of countries of the world, commas are used for decimal marks instead of periods. In this example with French locale, the comma is correctly handled as a decimal mark:
>>> import locale
>>> b = u'545,2222'
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.atof(b)
545.2222
The method locale.atoi is also available, but the argument should be an integer.
float(x) if '.' in x else int(x)
If you aren't averse to third-party modules, you could check out the fastnumbers module. It provides a function called fast_real that does exactly what this question is asking for and does it faster than a pure-Python implementation:
>>> from fastnumbers import fast_real
>>> fast_real("545.2222")
545.2222
>>> type(fast_real("545.2222"))
float
>>> fast_real("31")
31
>>> type(fast_real("31"))
int
Users codelogic and harley are correct, but keep in mind if you know the string is an integer (for example, 545) you can call int("545") without first casting to float.
If your strings are in a list, you could use the map function as well.
>>> x = ["545.0", "545.6", "999.2"]
>>> map(float, x)
[545.0, 545.60000000000002, 999.20000000000005]
>>>
It is only good if they're all the same type.
In Python, how can I parse a numeric string like "545.2222" to its corresponding float value, 542.2222? Or parse the string "31" to an integer, 31?
I just want to know how to parse a float string to a float, and (separately) an int string to an int.
It's good that you ask to do these separately. If you're mixing them, you may be setting yourself up for problems later. The simple answer is:
"545.2222" to float:
>>> float("545.2222")
545.2222
"31" to an integer:
>>> int("31")
31
Other conversions, ints to and from strings and literals:
Conversions from various bases, and you should know the base in advance (10 is the default). Note you can prefix them with what Python expects for its literals (see below) or remove the prefix:
>>> int("0b11111", 2)
31
>>> int("11111", 2)
31
>>> int('0o37', 8)
31
>>> int('37', 8)
31
>>> int('0x1f', 16)
31
>>> int('1f', 16)
31
If you don't know the base in advance, but you do know they will have the correct prefix, Python can infer this for you if you pass 0 as the base:
>>> int("0b11111", 0)
31
>>> int('0o37', 0)
31
>>> int('0x1f', 0)
31
Non-Decimal (i.e. Integer) Literals from other Bases
If your motivation is to have your own code clearly represent hard-coded specific values, however, you may not need to convert from the bases - you can let Python do it for you automatically with the correct syntax.
You can use the apropos prefixes to get automatic conversion to integers with the following literals. These are valid for Python 2 and 3:
Binary, prefix 0b
>>> 0b11111
31
Octal, prefix 0o
>>> 0o37
31
Hexadecimal, prefix 0x
>>> 0x1f
31
This can be useful when describing binary flags, file permissions in code, or hex values for colors - for example, note no quotes:
>>> 0b10101 # binary flags
21
>>> 0o755 # read, write, execute perms for owner, read & ex for group & others
493
>>> 0xffffff # the color, white, max values for red, green, and blue
16777215
Making ambiguous Python 2 octals compatible with Python 3
If you see an integer that starts with a 0, in Python 2, this is (deprecated) octal syntax.
>>> 037
31
It is bad because it looks like the value should be 37. So in Python 3, it now raises a SyntaxError:
>>> 037
File "<stdin>", line 1
037
^
SyntaxError: invalid token
Convert your Python 2 octals to octals that work in both 2 and 3 with the 0o prefix:
>>> 0o37
31
The question seems a little bit old. But let me suggest a function, parseStr, which makes something similar, that is, returns integer or float and if a given ASCII string cannot be converted to none of them it returns it untouched. The code of course might be adjusted to do only what you want:
>>> import string
>>> parseStr = lambda x: x.isalpha() and x or x.isdigit() and \
... int(x) or x.isalnum() and x or \
... len(set(string.punctuation).intersection(x)) == 1 and \
... x.count('.') == 1 and float(x) or x
>>> parseStr('123')
123
>>> parseStr('123.3')
123.3
>>> parseStr('3HC1')
'3HC1'
>>> parseStr('12.e5')
1200000.0
>>> parseStr('12$5')
'12$5'
>>> parseStr('12.2.2')
'12.2.2'
float("545.2222") and int(float("545.2222"))
The YAML parser can help you figure out what datatype your string is. Use yaml.load(), and then you can use type(result) to test for type:
>>> import yaml
>>> a = "545.2222"
>>> result = yaml.load(a)
>>> result
545.22220000000004
>>> type(result)
<type 'float'>
>>> b = "31"
>>> result = yaml.load(b)
>>> result
31
>>> type(result)
<type 'int'>
>>> c = "HI"
>>> result = yaml.load(c)
>>> result
'HI'
>>> type(result)
<type 'str'>
I use this function for that
import ast
def parse_str(s):
try:
return ast.literal_eval(str(s))
except:
return
It will convert the string to its type
value = parse_str('1') # Returns Integer
value = parse_str('1.5') # Returns Float
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else number_as_float
You could use json.loads:
>>> import json
>>> json.loads('123.456')
123.456
>>> type(_)
<class 'float'>
>>>
As you can see it becomes a type of float.
def num(s):
"""num(s)
num(3),num(3.7)-->3
num('3')-->3, num('3.7')-->3.7
num('3,700')-->ValueError
num('3a'),num('a3'),-->ValueError
num('3e4') --> 30000.0
"""
try:
return int(s)
except ValueError:
try:
return float(s)
except ValueError:
raise ValueError('argument is not a string of number')
You need to take into account rounding to do this properly.
i.e. - int(5.1) => 5
int(5.6) => 5 -- wrong, should be 6 so we do int(5.6 + 0.5) => 6
def convert(n):
try:
return int(n)
except ValueError:
return float(n + 0.5)
To typecast in Python use the constructor functions of the type, passing the string (or whatever value you are trying to cast) as a parameter.
For example:
>>>float("23.333")
23.333
Behind the scenes, Python is calling the objects __float__ method, which should return a float representation of the parameter. This is especially powerful, as you can define your own types (using classes) with a __float__ method so that it can be casted into a float using float(myobject).
Handles hex, octal, binary, decimal, and float
This solution will handle all of the string conventions for numbers (all that I know about).
def to_number(n):
''' Convert any number representation to a number
This covers: float, decimal, hex, and octal numbers.
'''
try:
return int(str(n), 0)
except:
try:
# Python 3 doesn't accept "010" as a valid octal. You must use the
# '0o' prefix
return int('0o' + n, 0)
except:
return float(n)
This test case output illustrates what I'm talking about.
======================== CAPTURED OUTPUT =========================
to_number(3735928559) = 3735928559 == 3735928559
to_number("0xFEEDFACE") = 4277009102 == 4277009102
to_number("0x0") = 0 == 0
to_number(100) = 100 == 100
to_number("42") = 42 == 42
to_number(8) = 8 == 8
to_number("0o20") = 16 == 16
to_number("020") = 16 == 16
to_number(3.14) = 3.14 == 3.14
to_number("2.72") = 2.72 == 2.72
to_number("1e3") = 1000.0 == 1000
to_number(0.001) = 0.001 == 0.001
to_number("0xA") = 10 == 10
to_number("012") = 10 == 10
to_number("0o12") = 10 == 10
to_number("0b01010") = 10 == 10
to_number("10") = 10 == 10
to_number("10.0") = 10.0 == 10
to_number("1e1") = 10.0 == 10
Here is the test:
class test_to_number(unittest.TestCase):
def test_hex(self):
# All of the following should be converted to an integer
#
values = [
# HEX
# ----------------------
# Input | Expected
# ----------------------
(0xDEADBEEF , 3735928559), # Hex
("0xFEEDFACE", 4277009102), # Hex
("0x0" , 0), # Hex
# Decimals
# ----------------------
# Input | Expected
# ----------------------
(100 , 100), # Decimal
("42" , 42), # Decimal
]
values += [
# Octals
# ----------------------
# Input | Expected
# ----------------------
(0o10 , 8), # Octal
("0o20" , 16), # Octal
("020" , 16), # Octal
]
values += [
# Floats
# ----------------------
# Input | Expected
# ----------------------
(3.14 , 3.14), # Float
("2.72" , 2.72), # Float
("1e3" , 1000), # Float
(1e-3 , 0.001), # Float
]
values += [
# All ints
# ----------------------
# Input | Expected
# ----------------------
("0xA" , 10),
("012" , 10),
("0o12" , 10),
("0b01010" , 10),
("10" , 10),
("10.0" , 10),
("1e1" , 10),
]
for _input, expected in values:
value = to_number(_input)
if isinstance(_input, str):
cmd = 'to_number("{}")'.format(_input)
else:
cmd = 'to_number({})'.format(_input)
print("{:23} = {:10} == {:10}".format(cmd, value, expected))
self.assertEqual(value, expected)
Pass your string to this function:
def string_to_number(str):
if("." in str):
try:
res = float(str)
except:
res = str
elif(str.isdigit()):
res = int(str)
else:
res = str
return(res)
It will return int, float or string depending on what was passed.
String that is an int
print(type(string_to_number("124")))
<class 'int'>
String that is a float
print(type(string_to_number("12.4")))
<class 'float'>
String that is a string
print(type(string_to_number("hello")))
<class 'str'>
String that looks like a float
print(type(string_to_number("hel.lo")))
<class 'str'>
There is also regex, because sometimes string must be prepared and normalized before casting to a number:
import re
def parseNumber(value, as_int=False):
try:
number = float(re.sub('[^.\-\d]', '', value))
if as_int:
return int(number + 0.5)
else:
return number
except ValueError:
return float('nan') # or None if you wish
Usage:
parseNumber('13,345')
> 13345.0
parseNumber('- 123 000')
> -123000.0
parseNumber('99999\n')
> 99999.0
And by the way, something to verify you have a number:
import numbers
def is_number(value):
return isinstance(value, numbers.Number)
# Will work with int, float, long, Decimal
a = int(float(a)) if int(float(a)) == float(a) else float(a)
This is a corrected version of Totoro's answer.
This will try to parse a string and return either int or float depending on what the string represents. It might rise parsing exceptions or have some unexpected behaviour.
def get_int_or_float(v):
number_as_float = float(v)
number_as_int = int(number_as_float)
return number_as_int if number_as_float == number_as_int else
number_as_float
If you are dealing with mixed integers and floats and want a consistent way to deal with your mixed data, here is my solution with the proper docstring:
def parse_num(candidate):
"""Parse string to number if possible
It work equally well with negative and positive numbers, integers and floats.
Args:
candidate (str): string to convert
Returns:
float | int | None: float or int if possible otherwise None
"""
try:
float_value = float(candidate)
except ValueError:
return None
# Optional part if you prefer int to float when decimal part is 0
if float_value.is_integer():
return int(float_value)
# end of the optional part
return float_value
# Test
candidates = ['34.77', '-13', 'jh', '8990', '76_3234_54']
res_list = list(map(parse_num, candidates))
print('Before:')
print(candidates)
print('After:')
print(res_list)
Output:
Before:
['34.77', '-13', 'jh', '8990', '76_3234_54']
After:
[34.77, -13, None, 8990, 76323454]
Use:
def num(s):
try:
for each in s:
yield int(each)
except ValueError:
yield float(each)
a = num(["123.55","345","44"])
print a.next()
print a.next()
This is the most Pythonic way I could come up with.
If you don't want to use third party modules the following might be the most robust solution:
def string_to_int_or_float(s):
try:
f = float(s) # replace s with str(s) if you are not sure that s is a string
except ValueError:
print("Provided string '" + s + "' is not interpretable as a literal number.")
raise
try:
i = int(str(f).rstrip('0').rstrip('.'))
except:
return f
return i
It might not be the fastest, but it handles correctly literal numbers where many other solutions fail, such as:
>>> string_to_int_or_float('789.')
789
>>> string_to_int_or_float('789.0')
789
>>> string_to_int_or_float('12.3e2')
1230
>>> string_to_int_or_float('12.3e-2')
0.123
>>> string_to_int_or_float('4560e-1')
456
>>> string_to_int_or_float('4560e-2')
45.6
You can simply do this by
s = '542.22'
f = float(s) # This converts string data to float data with a decimal point
print(f)
i = int(f) # This converts string data to integer data by just taking the whole number part of it
print(i)
For more information on parsing of data types check on python documentation!
This is a function which will convert any object (not just str) to int or float, based on if the actual string supplied looks like int or float. Further if it's an object which has both __float and __int__ methods, it defaults to using __float__
def conv_to_num(x, num_type='asis'):
'''Converts an object to a number if possible.
num_type: int, float, 'asis'
Defaults to floating point in case of ambiguity.
'''
import numbers
is_num, is_str, is_other = [False]*3
if isinstance(x, numbers.Number):
is_num = True
elif isinstance(x, str):
is_str = True
is_other = not any([is_num, is_str])
if is_num:
res = x
elif is_str:
is_float, is_int, is_char = [False]*3
try:
res = float(x)
if '.' in x:
is_float = True
else:
is_int = True
except ValueError:
res = x
is_char = True
else:
if num_type == 'asis':
funcs = [int, float]
else:
funcs = [num_type]
for func in funcs:
try:
res = func(x)
break
except TypeError:
continue
else:
res = x
By using int and float methods we can convert a string to integer and floats.
s="45.8"
print(float(s))
y='67'
print(int(y))
For numbers and characters together:
string_for_int = "498 results should get"
string_for_float = "498.45645765 results should get"
First import re:
import re
# For getting the integer part:
print(int(re.search(r'\d+', string_for_int).group())) #498
# For getting the float part:
print(float(re.search(r'\d+\.\d+', string_for_float).group())) #498.45645765
For easy model:
value1 = "10"
value2 = "10.2"
print(int(value1)) # 10
print(float(value2)) # 10.2

Categories

Resources