How to check whether string might be type-cast to float in Python?
Question:
Is there some function like str.isnumeric
but applicable to float?
'13.37'.isnumeric() #False
I still use this:
def isFloat(string):
try:
float(string)
return True
except ValueError:
return False
Answers:
Your code is absolutely fine. Regex based solutions are more likely to be error prone.
Quick testing with timeit
reveals float(str_val)
is indeed faster than re.match()
>>> timeit.timeit('float("-1.1")')
1.2833082290601467
>>> timeit.timeit(r"pat.match('-1.1')", "import re; pat=re.compile(r'^-?d*.?d+(?:[Ee]-?d+)?$');")
1.5084138986904527
And the regex used above fails one edge case, it can’t match '-1.'
, although float()
will happily convert it to proper float value.
isinstance(myVariable, float)
will work if you’re testing a floating point variable.
Edit: Spoke too soon, didn’t fully understand what you were trying to get.
As Imran says, your code is absolutely fine as shown.
However, it does encourage clients of isFloat
down the “Look Before You Leap” path instead of the more Pythonic “Easier to Ask Forgiveness than Permission” path.
It’s more Pythonic for clients to assume they have a string representing a float but be ready to handle the exception that will be thrown if it isn’t.
This approach also has the nice side-effect of converting the string to a float once instead of twice.
There’s a catch though:
float(‘nan’) returns nan, no exception raised 😉
A more complete generalization:
def strType(xstr):
try:
int(xstr)
return 'int'
except:
try:
float(xstr)
return 'float'
except:
try:
complex(xstr)
return 'complex'
except:
return 'str'
print("4", strType("4"))
print("12345678901234567890", strType("12345678901234567890"))
print("4.1", strType("4.1"))
print("4.1+3j", strType("4.1+3j"))
print("a", strType("a"))
Extending from @Imran’s results:
>>> timeit('float("-1.1")', number=10000000)
1.365271806716919
>>> timeit(r"isfloat('-1.1')", """def isfloat(s): t = s.partition('.');
return t[1] and t[0].isdigit() and (not t[2] or t[2].isdigit());""",
number=10000000)
2.565232992172241
>>> timeit(r"pat.match('-1.1')", "import re; pat=re.compile(r'^-?d*.?d+(
...: ?:[Ee]-?d+)?$');", number=10000000)
3.258622169494629
My partition
solution is much faster than regex, but slower than float
; however has the advantage of not raising errors (so you can use it in e.g.: comprehensions).
This handles edge conditions like 1.
, but not specialisations like NaN
.
Is there some function like str.isnumeric
but applicable to float?
'13.37'.isnumeric() #False
I still use this:
def isFloat(string):
try:
float(string)
return True
except ValueError:
return False
Your code is absolutely fine. Regex based solutions are more likely to be error prone.
Quick testing with timeit
reveals float(str_val)
is indeed faster than re.match()
>>> timeit.timeit('float("-1.1")')
1.2833082290601467
>>> timeit.timeit(r"pat.match('-1.1')", "import re; pat=re.compile(r'^-?d*.?d+(?:[Ee]-?d+)?$');")
1.5084138986904527
And the regex used above fails one edge case, it can’t match '-1.'
, although float()
will happily convert it to proper float value.
isinstance(myVariable, float)
will work if you’re testing a floating point variable.
Edit: Spoke too soon, didn’t fully understand what you were trying to get.
As Imran says, your code is absolutely fine as shown.
However, it does encourage clients of isFloat
down the “Look Before You Leap” path instead of the more Pythonic “Easier to Ask Forgiveness than Permission” path.
It’s more Pythonic for clients to assume they have a string representing a float but be ready to handle the exception that will be thrown if it isn’t.
This approach also has the nice side-effect of converting the string to a float once instead of twice.
There’s a catch though:
float(‘nan’) returns nan, no exception raised 😉
A more complete generalization:
def strType(xstr):
try:
int(xstr)
return 'int'
except:
try:
float(xstr)
return 'float'
except:
try:
complex(xstr)
return 'complex'
except:
return 'str'
print("4", strType("4"))
print("12345678901234567890", strType("12345678901234567890"))
print("4.1", strType("4.1"))
print("4.1+3j", strType("4.1+3j"))
print("a", strType("a"))
Extending from @Imran’s results:
>>> timeit('float("-1.1")', number=10000000)
1.365271806716919
>>> timeit(r"isfloat('-1.1')", """def isfloat(s): t = s.partition('.');
return t[1] and t[0].isdigit() and (not t[2] or t[2].isdigit());""",
number=10000000)
2.565232992172241
>>> timeit(r"pat.match('-1.1')", "import re; pat=re.compile(r'^-?d*.?d+(
...: ?:[Ee]-?d+)?$');", number=10000000)
3.258622169494629
My partition
solution is much faster than regex, but slower than float
; however has the advantage of not raising errors (so you can use it in e.g.: comprehensions).
This handles edge conditions like 1.
, but not specialisations like NaN
.