Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Pythonic way to determine if a string is a number

5 views
Skip to first unread message

pyt...@bdurham.com

unread,
Feb 15, 2009, 12:46:56 PM2/15/09
to pytho...@python.org
What's the Pythonic way to determine if a string is a number? By
number I mean a valid integer or float.

I searched the string and cMath libraries for a similar function
without success. I can think of at least 3 or 4 ways to build my
own function.

Here's what I came up with as a proof-of-concept. Are there
'better' ways to perform this type of test?

Thanks,
Malcolm

<code>
def isnumber( input ):
try:
if '.' in input:
num = float( input )
else:
num = int( input )
return True

except ValueError:
return False

if __name__ == '__main__':
tests = """
12
-12
-12.34
.0
.
1 2 3
1 . 2
just text
"""

for test in tests.split( '\n' ):
print 'test (%0s), isnumber: %1s' % \
( test.strip(), isnumber( test ) )

</code>

Christian Heimes

unread,
Feb 15, 2009, 12:51:57 PM2/15/09
to pytho...@python.org
pyt...@bdurham.com schrieb:

> What's the Pythonic way to determine if a string is a number? By
> number I mean a valid integer or float.
>
> I searched the string and cMath libraries for a similar function
> without success. I can think of at least 3 or 4 ways to build my
> own function.
>
> Here's what I came up with as a proof-of-concept. Are there
> 'better' ways to perform this type of test?
>
> Thanks,
> Malcolm
>
> <code>
> def isnumber( input ):
> try:
> if '.' in input:
> num = float( input )
> else:
> num = int( input )
> return True
>
> except ValueError:
> return False

You code doesn't check for several float representations like "1e10",
"1E10", "inf" and "nan".

Christian

Philip Semanchuk

unread,
Feb 15, 2009, 1:03:36 PM2/15/09
to python-list (General)

On Feb 15, 2009, at 12:46 PM, pyt...@bdurham.com wrote:

> What's the Pythonic way to determine if a string is a number? By
> number I mean a valid integer or float.


try:
int(number)
is_an_int = True
except:
is_an_int = False

try:
float(number)
is_a_float = True
except:
is_a_float = False

is_a_number = (is_an_int or is_a_float)


Roy Smith

unread,
Feb 15, 2009, 1:15:38 PM2/15/09
to
In article <mailman.9571.1234720...@python.org>,
pyt...@bdurham.com wrote:

> What's the Pythonic way to determine if a string is a number? By
> number I mean a valid integer or float.

try:
int(myString)
except ValueError:
print "That's bogus, man"

Christian Heimes

unread,
Feb 15, 2009, 1:27:47 PM2/15/09
to pytho...@python.org
Philip Semanchuk schrieb:

>
> On Feb 15, 2009, at 12:46 PM, pyt...@bdurham.com wrote:
>
>> What's the Pythonic way to determine if a string is a number? By
>> number I mean a valid integer or float.
>
>
> try:
> int(number)
> is_an_int = True
> except:
> is_an_int = False

Please don't teach new Python developers to use bare excepts. In fact
never use bare excepts at all!

Christian

MRAB

unread,
Feb 15, 2009, 1:56:53 PM2/15/09
to pytho...@python.org
Roy Smith wrote:
> In article <mailman.9571.1234720...@python.org>,
> pyt...@bdurham.com wrote:
>
>> What's the Pythonic way to determine if a string is a number? By
>> number I mean a valid integer or float.
>
> try:
> int(myString)
It could be a float, so:

float(myString)

This will work even if it's an int.

Roy Smith

unread,
Feb 15, 2009, 2:01:12 PM2/15/09
to
In article <mailman.9577.1234722...@python.org>,
Christian Heimes <li...@cheimes.de> wrote:

I agree that the bare except is incorrect in this situation, but I don't
agree that you should *never* use them.

They make sense when you need to recover from any error that may occur,
possibly as the last resort after catching and dealing with more specific
exceptions. In an unattended embedded system (think Mars Rover), the
top-level code might well be:

while 1:
try:
main()
except:
reset()

or perhaps even (Range Safety Controller):

try:
main()
except:
self_destruct()

pyt...@bdurham.com

unread,
Feb 15, 2009, 3:05:01 PM2/15/09
to pytho...@python.org
Thanks for everyone's feedback. I believe my original post's code
(updated following my signature) was in line with this list's feedback.

Christian: Thanks for reminding me about exponential formats. My updated
code accounts for these type of numbers. I don't need to handle inf or
nan values. My original code's except catches an explicit ValueError
exception per your concern about bare excepts.

Malcolm

<code>
# str_to_num.py

def isnumber( input ):
try:

num = float( input )

return True

except ValueError:
return False

if __name__ == '__main__':


tests = """
12
-12
-12.34
.0
.
1 2 3
1 . 2

1e10
1E10
inf
nan

12 and text

Christian Heimes

unread,
Feb 15, 2009, 3:04:49 PM2/15/09
to pytho...@python.org
Roy Smith wrote:
> I agree that the bare except is incorrect in this situation, but I don't
> agree that you should *never* use them.

A bare except should be used when followed by a raise

try:
func()
except:
log_error()
raise

> They make sense when you need to recover from any error that may occur,
> possibly as the last resort after catching and dealing with more specific
> exceptions. In an unattended embedded system (think Mars Rover), the
> top-level code might well be:
>
> while 1:
> try:
> main()
> except:
> reset()

Do you really want to except SystemExit, KeyboardInterrupt, MemoryError
and SyntaxError?

Christian

Tim Golden

unread,
Feb 15, 2009, 3:08:53 PM2/15/09
to pytho...@python.org
pyt...@bdurham.com wrote:
> <code>
> # str_to_num.py
>
> def isnumber( input ):
> try:
> num = float( input )
> return True
>
> except ValueError:
> return False


Just for the info, Malcolm, you don't actually
need to assign the result of float (input)
to anything if you don't need to use it. All
you're looking for is the exception. Let the
intepreter convert it and then throw it away.

Also, as an alternative style which can be more
appropriate depending on the structure and intention
of what you're doing, you can use the else: clause
of the try-except block.

try:
float (input)
except ValueError:
return False
else:
return True

TJG

pyt...@bdurham.com

unread,
Feb 15, 2009, 3:40:47 PM2/15/09
to Tim Golden, pytho...@python.org
Tim,

> Just for the info, Malcolm, you don't actually need to assign the result of float (input) to anything if you don't need to use it. All you're looking for is the exception. Let the intepreter convert it and then throw it away.

Yes!

> Also, as an alternative style which can be more appropriate depending on the structure and intention of what you're doing, you can use the else: clause of the try-except block.
>
> try:
> float (input)
> except ValueError:
> return False
> else:
> return True

I follow the semantics, but I don't know why I would prefer the try/else
technique over the simpler:

try:


float( input )
return True
except ValueError:
return False

Thank you for your feedback,

Malcolm

Mel

unread,
Feb 15, 2009, 7:05:36 PM2/15/09
to
Christian Heimes wrote:
> Roy Smith wrote:

>> They make sense when you need to recover from any error that may occur,
>> possibly as the last resort after catching and dealing with more specific
>> exceptions. In an unattended embedded system (think Mars Rover), the
>> top-level code might well be:
>>
>> while 1:
>> try:
>> main()
>> except:
>> reset()
>
> Do you really want to except SystemExit, KeyboardInterrupt, MemoryError
> and SyntaxError?

Exactly. A normal program should never do anything more comprehensive than

try:
some_function ()
except StandardError:
some_handling ()

IMHO

Mel.

Scott David Daniels

unread,
Feb 15, 2009, 7:13:41 PM2/15/09
to
pyt...@bdurham.com wrote:
> Thanks for everyone's feedback....

> def isnumber( input ):
> try:
> num = float( input )
> return True
>
> except ValueError:
> return False

Pretty good, but what about 0x23?

def isnumber( input ):
try:
num = float(input)
return True
except ValueError:

try:
num = int(input, 0) # Convert to int, base spec in arg


return True
except ValueError:
return False


--Scott David Daniels
Scott....@Acm.Org

Philip Semanchuk

unread,
Feb 15, 2009, 8:35:17 PM2/15/09
to python-list (General)

On Feb 15, 2009, at 1:27 PM, Christian Heimes wrote:

> Philip Semanchuk schrieb:
>>
>> On Feb 15, 2009, at 12:46 PM, pyt...@bdurham.com wrote:
>>
>>> What's the Pythonic way to determine if a string is a number? By
>>> number I mean a valid integer or float.
>>
>>
>> try:
>> int(number)
>> is_an_int = True
>> except:
>> is_an_int = False
>
> Please don't teach new Python developers to use bare excepts.

Good point; my example is lazy.

I should know better as I myself got burned on bare excepts a few
times when I started with Python.

John Machin

unread,
Feb 15, 2009, 8:37:19 PM2/15/09
to

Do you care about numbers that are representable as an int, but are
treated as inf by float()?

For example:
| >>> s = '1' * 310
| >>> float(s)
| inf
| >>> a = int(s)
| >>> # OK

Roy Smith

unread,
Feb 15, 2009, 9:35:20 PM2/15/09
to
In article <gnaak5$1nek$1...@services.telesweet.net>,
Mel <mwi...@the-wire.com> wrote:

> Christian Heimes wrote:
> > Roy Smith wrote:
>
> >> They make sense when you need to recover from any error that may occur,
> >> possibly as the last resort after catching and dealing with more specific
> >> exceptions. In an unattended embedded system (think Mars Rover), the
> >> top-level code might well be:
> >>
> >> while 1:
> >> try:
> >> main()
> >> except:
> >> reset()
> >
> > Do you really want to except SystemExit, KeyboardInterrupt, MemoryError
> > and SyntaxError?

Absolutely. Let's take my example -- you're writing software for a Mars
Rover. I have no idea how you might get a MemoryError, but let's say you
do. Which would you rather do, perform a system reset, or print a stack
trace and wait for a friendly Martian to come along and reboot you?

You may think I'm being silly, but I'm dead serious. The many layers of
"It's impossible for this to happen, but if it does let's do something to
try and recover" processing saved that mission several times over. In some
applications, there's no such thing as "halt".

pyt...@bdurham.com

unread,
Feb 16, 2009, 12:28:39 AM2/16/09
to Scott David Daniels, pytho...@python.org
Scott,

> Pretty good, but what about 0x23?
>

<snipped>


> num = int(input, 0) # Convert to int, base spec in arg
>

Very nice! I wasn't familiar with the use of 0 as a radix value. A quick
visit back to the documentation and I'm an enlightened man :)

Thanks for your feedback,

Malcolm

pyt...@bdurham.com

unread,
Feb 16, 2009, 12:37:22 AM2/16/09
to John Machin, pytho...@python.org
John,

> Do you care about numbers that are representable as an int, but are treated as inf by float()?
>
> For example:
> | >>> s = '1' * 310
> | >>> float(s)
> | inf
> | >>> a = int(s)
> | >>> # OK

My code range checks all numbers once they've been parsed, so I don't
believe this will be a problem for me.

However, I appreciate you pointing out this behavior because I was
unaware of this subtle nuance. I'll make sure to add this to our code
review checklist.

Python Nutter

unread,
Feb 16, 2009, 2:04:54 AM2/16/09
to pytho...@python.org
Type casting seems to be the wrong way to go about this.

teststring = '15719'
teststring.isdigit()
returns True

That takes care of integers.

from string import digits
digits
'0123456789'

now you have all the digits and you can do set testing in your logic
to see if the teststring has anything in digits

A dumb way to test is alphanumeric

teststring2 = '105.22'
teststring2.isalnum()
returns True

now you can go on from there and test to further to eliminate
'abcd385laf8' which on alnum() also returns true.

Have fun,
Cheers,
PN


2009/2/16 <pyt...@bdurham.com>:


> What's the Pythonic way to determine if a string is a number? By
> number I mean a valid integer or float.
>

> I searched the string and cMath libraries for a similar function
> without success. I can think of at least 3 or 4 ways to build my
> own function.
>
> Here's what I came up with as a proof-of-concept. Are there
> 'better' ways to perform this type of test?
>
> Thanks,
> Malcolm
>
> <code>

> def isnumber( input ):
> try:

> if '.' in input:


> num = float( input )

> else:
> num = int( input )


> return True
>
> except ValueError:
> return False
>
> if __name__ == '__main__':
> tests = """
> 12
> -12
> -12.34
> .0
> .
> 1 2 3
> 1 . 2

> just text
> """
>
> for test in tests.split( '\n' ):
> print 'test (%0s), isnumber: %1s' % \
> ( test.strip(), isnumber( test ) )
>
> </code>

> --
> http://mail.python.org/mailman/listinfo/python-list
>

Python Nutter

unread,
Feb 16, 2009, 2:09:00 AM2/16/09
to pytho...@python.org
silly me, forgot to mention

build a set from digits + '.' and use that for testing.

Cheers,
PN


2009/2/16 Python Nutter <python...@gmail.com>:

Tino Wildenhain

unread,
Feb 16, 2009, 2:14:33 AM2/16/09
to Python Nutter, pytho...@python.org
Python Nutter wrote:
> Type casting seems to be the wrong way to go about this.
>
> teststring = '15719'
> teststring.isdigit()
> returns True

Actually its instantiating not type casting and it works
by using the type's actual description of the data it
accepts. This looks pretty good approach instead of trying
to copy (incomplete as it has been shown not only digits and
. constitute a float) already implemented code.

Of course if you want to limit the range of accepted data
even more, then isdigit and friends can be used -
maybe you could time both approaches with a set of data.

Regards
Tino

Tino Wildenhain

unread,
Feb 16, 2009, 2:18:42 AM2/16/09
to Roy Smith, pytho...@python.org

Yeah, having your mars rower forever running in a loop to try to convert
some random string to a number is sure something you want to achieve.

Tino

Nick Craig-Wood

unread,
Feb 16, 2009, 4:31:55 PM2/16/09
to
pyt...@bdurham.com <pyt...@bdurham.com> wrote:
> Thanks for everyone's feedback. I believe my original post's code
> (updated following my signature) was in line with this list's feedback.
>
> Christian: Thanks for reminding me about exponential formats. My updated
> code accounts for these type of numbers. I don't need to handle inf or
> nan values. My original code's except catches an explicit ValueError
> exception per your concern about bare excepts.
>
> Malcolm
>
> <code>
> # str_to_num.py
>
> def isnumber( input ):
> try:
> num = float( input )
> return True
>
> except ValueError:
> return False

That is a fine solution.

Last time I had to solve this I had a specific format of number to
parse - I didn't want to include all the python formats. This is what
I came up with... This particular code returns the converted number
or 0.0 - adjust as you see fit!

import re

_float_pattern = re.compile(r"^\s*([-+]?(\d*\.)?\d+([eE][-+]?\d+)?)")

def atof(value):
"""
Convert a string to an float in the same way the c-library atof()
does. Ie only converting as much as it can and returning 0.0 for
an error.
"""
match = _float_pattern.search(value)
if match:
return float(match.group(1))
return 0.0

>>> atof("15.5 Sausages")
15.5
>>> atof(" 17.2")
17.199999999999999
>>> atof("0x12")
0.0
>>> atof("8.3.2")
8.3000000000000007
>>> atof("potato")
0.0
>>>

--
Nick Craig-Wood <ni...@craig-wood.com> -- http://www.craig-wood.com/nick

Paddy

unread,
Feb 17, 2009, 1:34:49 AM2/17/09
to

Their is a good answer given on Rosetta Code here:
http://www.rosettacode.org/wiki/IsNumeric#Python

- Paddy.

Steven D'Aprano

unread,
Feb 17, 2009, 7:23:32 AM2/17/09
to
Roy Smith wrote:

>> > Do you really want to except SystemExit, KeyboardInterrupt, MemoryError
>> > and SyntaxError?
>
> Absolutely. Let's take my example -- you're writing software for a Mars
> Rover. I have no idea how you might get a MemoryError, but let's say you
> do. Which would you rather do, perform a system reset, or print a stack
> trace and wait for a friendly Martian to come along and reboot you?
>
> You may think I'm being silly, but I'm dead serious. The many layers of
> "It's impossible for this to happen, but if it does let's do something to
> try and recover" processing saved that mission several times over. In
> some applications, there's no such thing as "halt".

Okay, but that surely falls under chapter 18 of the "Advanced Python
Programming for the Mars Rover" book rather than chapter 5 of "Newbies
Guide to Python".

In general, the right thing to do for unexpected exemptions is to let them
halt the program so you can find out about them and fix the bug, not to
hide the exception. There may be exceptions (pun intended) to this general
principle, but they're fairly unusual.


--
Steven

Roy Smith

unread,
Feb 17, 2009, 9:55:15 AM2/17/09
to
In article <01aaa1da$0$20629$c3e...@news.astraweb.com>,

Steven D'Aprano <st...@pearwood.info> wrote:

> Okay, but that surely falls under chapter 18 of the "Advanced Python
> Programming for the Mars Rover" book rather than chapter 5 of "Newbies
> Guide to Python".

Well, sure, but this thread started out with my taking, ahem, exception to
the statement, "never use bare excepts at all". I agree that doing so is
not typical, and not the kind of habit that new programmers should form
because it's not the kind of situation new programmers are likely to be
involved in. But, "never" was too strong a word.

Floris Bruynooghe

unread,
Feb 17, 2009, 10:12:02 AM2/17/09
to

Hmm, most places advocate or even outright recommend derriving your
own exceptions from Exception and not from StandardError. So maybe
your catch-all should be Exception? In that case you would be
catching warnings though, no idea what influence that has on the
warning system.

Regards
Floris

PS: Does anybody know why StopIterantion derrives from Exception while
GeneratorExit derrives from BaseException? This could be as annoying/
confusing as Warning.

Floris Bruynooghe

unread,
Feb 17, 2009, 10:29:49 AM2/17/09
to
On Feb 16, 7:09 am, Python Nutter <pythonnut...@gmail.com> wrote:
> silly me, forgot to mention
>
> build a set from digits + '.' and use that for testing.

`.' is locale dependent. Some locales might use `,' instead and maybe
there's even more out there that I don't know of. So developing this
yourself from scratch seems dangerous, let it bubble down to libc
which should handle it correctly.


Regards
Floris

Paddy O'Loughlin

unread,
Feb 17, 2009, 10:35:18 AM2/17/09
to Python Nutter, pytho...@python.org
2009/2/16 Python Nutter <python...@gmail.com>:

> silly me, forgot to mention
>
> build a set from digits + '.' and use that for testing.
>
> Cheers,
> PN
>
>
> 2009/2/16 Python Nutter <python...@gmail.com>:
>> Type casting seems to be the wrong way to go about this.
>>
>> teststring = '15719'
>> teststring.isdigit()
>> returns True
>>
>> That takes care of integers.
>>
>> from string import digits
>> digits
>> '0123456789'
>>
>> now you have all the digits and you can do set testing in your logic
>> to see if the teststring has anything in digits
>>
>> A dumb way to test is alphanumeric
>>
>> teststring2 = '105.22'
>> teststring2.isalnum()
>> returns True
>>
>> now you can go on from there and test to further to eliminate
>> 'abcd385laf8' which on alnum() also returns true.

Hmmm, this doesn't seem right to me.

Unless I'm missing something, won't your code think that "123.123.123"
is numeric? What about scientific or engineering notation with
exponents?

What's wrong with using python's own casting rules (given that you are
trying to emulate the way python behaves? Or, alternatively, using a
regular expression (as Nick Craig-Wood did).

Given these solutions, type-conversion and catching the ValueError
appears, to me, to be correct, the most concise, and the most readable
solution.

Of course, if you want to use your own set of rules for number
encoding, then building your own regular expression would seem to be
the right way to go.

Paddy

--
"Ray, when someone asks you if you're a god, you say YES!"

pyt...@bdurham.com

unread,
Feb 17, 2009, 10:45:48 AM2/17/09
to Roy Smith, pytho...@python.org
Original poster here: Just for the record, my *original* post did
include an explicit trapping of the ValueError exception. :)

My point is that the coaching offered by this forum does not always fall
on deaf ears.

Thanks for everyone's help on this and all the other posts in this
forum.

Regards,
Malcolm

0 new messages