28

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
mskfisher
  • 3,291
  • 4
  • 35
  • 48
Andrew
  • 8,330
  • 11
  • 45
  • 78
  • A more consistent and complete answer: ` 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")) ` – juanfal Nov 12 '19 at 15:18
  • 3
    '13.37'.replace(".","").isnumeric(): – Grigory Ilizirov Aug 24 '20 at 12:38
  • I like @GrigoryIlizirov answer the best because it doesn't invoke an exception. – Nigel Feasey Nov 11 '20 at 00:46

6 Answers6

12

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.

Jon-Eric
  • 16,977
  • 9
  • 65
  • 97
  • 4
    +1: @pingvinus: Please don't waste time writing such things. Just write your real application. If it throws a `ValueError` that means the input wasn't valid float and an overall exception handler can report this. There's no need to pre-check for float values, since the `float` function does this right when you need it. And always correctly. – S.Lott Mar 01 '10 at 16:14
  • Although i see the point in try catch, I think that doing it a lot "could" be expensive to handle the exception. I am surprised that the isfloat helper is not available, – Peter Moore May 23 '18 at 17:45
  • @S.Lott That's not necessarily true. There are very good applications for a function like this when you need to make a decision based on an unknown value. This is far more readable. – Nilpo Nov 03 '18 at 00:53
4

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"))
juanfal
  • 113
  • 5
Leandro Lima
  • 101
  • 1
  • 6
2

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.

Imran
  • 87,203
  • 23
  • 98
  • 131
  • I think I remember seeing a thread about this on a mailing list a long time ago. The gist was that float() and a regex were about the same speed. – Richard Levasseur Mar 01 '10 at 15:52
  • It's not a Python-way I think - 6 lines of code to solve common problem. But, thanks. – Andrew Mar 01 '10 at 15:53
  • Using re.compile will make the regexp pretty much the same speed as float(). – mthurlin Mar 01 '10 at 16:02
  • 2
    @Imran: your performance comparison is not correct, while `float` would be faster, you need to compile regex outside of the execution loop, it needs to be re-used for that method to be practical. – SilentGhost Mar 01 '10 at 16:03
  • Performance with compiled regex is even worse :P. How could that be? The `setup` statement in `timeit.timeit` is eval'ed just once, isn't it? – Imran Mar 01 '10 at 16:07
  • gosh, you need to do `pat.match('1.1')`. Also `match` is always starting from the start of the subject string, no `^` required. – SilentGhost Mar 01 '10 at 16:09
  • @SilentGhost: Thanks, now regex's performance is lot closer to `float` :) – Imran Mar 01 '10 at 16:16
  • The regexp needs to also match floats written with an exponent, for example '10e-2' –  Mar 01 '10 at 18:31
  • @Paul: Updated the regex to match exponent – Imran Mar 01 '10 at 20:50
  • What about when isFloat() fails? How long does throwing and catching an exception/error take? – Silveri Sep 14 '15 at 14:56
1

There's a catch though: float('nan') returns nan, no exception raised ;)

PyAtl
  • 19
  • 1
  • 1
    `nan` and `inf` (positive and negative) are floats, as `1.e9`. [GNU libc](http://www.gnu.org/software/libc/manual/html_node/Infinity-and-NaN.html), [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point)... so that's valid – bufh Aug 09 '16 at 12:45
0

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.

A T
  • 13,008
  • 21
  • 97
  • 158
-2

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.

wersimmon
  • 2,809
  • 3
  • 22
  • 35