I couldn\'t find another answer when I wanted this, so I thought I would post my own solution for anyone else and also get corrections if I\'ve done something wrong.
This is one time where it's probably better to get permission first than ask for forgiveness later which is usually considered the 'Pythonic' way to do things and usually involves try/except
. So something simple like this might be good enough:
v = float(s) if '.' in s or 'e' in s.lower() else int(s)
Since there's more than one character that can signal a floating point number, you could also check for one of them these following other ways:
import re
pattern = re.compile(r'[.eE]')
v = float(s) if pattern.findall(s) else int(s)
or
chars = set('.eE')
v = float(s) if any((c in chars) for c in s) else int(s)
Lastly, on a slightly different track, if you wanted floating point whole numbers to become integers, you could do the following, which is similar to @John Machin's "_dammit_
" function:
v = int(float(s)) if int(float(s)) == float(s) else float(s)
eval()
is a function that accepts a string and processes it as Python code. When given any kind of literal as a string, it will return a Python object containing that value.
However, from a security standpoint, this is a bad idea, as someone could potentially feed instructions that crash or tamper with your program. You could require it to be a certain set of characters before processing, i.e.:
eval(s) if not set(s).difference('0123456789.') else None
This still probably isn't worth the headache, though. That said, you can get fancy, and allow expressions with calculations as well... and that might be worth trying!
num = lambda s: eval(s) if not set(s).difference('0123456789. *+-/e') else None
>>> num('10')
10
>>> num('10.0')
10.0
>>> num('1e3')
1000.0
>>> num('4.8 * 10**34')
4.8e+34
>>> num('1+2/3')
1.6666666666666665
Trying to detect a float isn't easy, but detecting a possible integer is easier.
I would try to check if the string contains only digits (disregarding possible leading spaces or sign) and convert to float or integer accordingly:
lst = ['1' , '2.2' , ' -3','+5']
result = [int(x) if x.lstrip(" -+").isdigit() else float(x) for x in lst]
print(result)
prints:
[1, 2.2, -3, 5]
def int_float_none(x):
# it may be already int or float
if isinstance(x, (int, float)):
return x
# all int like strings can be converted to float so int tries first
try:
return int(x)
except (TypeError, ValueError):
pass
try:
return float(x)
except (TypeError, ValueError):
return None
Function above for any object passed will return int or float conversion or None.
def int_or_float(s):
try:
return int(s)
except ValueError:
return float(s)
If you want something like "10.0000"
converted to int, try this:
def int_dammit_else_float(s):
f = float(s)
i = int(f)
return i if i == f else f
What result do you want for input like "1e25"
?