[Tutor] output is all integer when there should be some floats
Steven D'Aprano
steve at pearwood.info
Sun Apr 26 13:02:57 CEST 2015
On Sat, Apr 25, 2015 at 09:18:53PM -0700, Jim Mooney Py3winXP wrote:
> It seems odd to me that there are three tests to see if user input is
> digits - isdecimal, isdigit, isnumeric, but nothing to test for a float
> unless you use a try - except. Or did I miss something?
Yes -- the string tests don't specifically test for valid numbers, only
digit characters.
If we go back deep into the mists of time, when dinosaurs ruled the
earth, Python ints were not unlimited in size. If you tried to create an
integer that was too big, you would get an exception, either an
OverflowError or a ValueError depending on what you tried to do.
Even today, just because a string is all digits doesn't mean that you
can successfully turn it into an int. You may run out of memory, if you
have millions of digits.
The right way to check is a string is numeric is to try to convert it
into a number and see what happens. The string methods are too strict,
and will prohibit perfectly good numeric strings:
py> s = ' -123 '
py> s.isdigit()
False
py> int(s)
-123
(In my experience, the isdigit etc. methods are really only useful for
testing individual characters.)
Instead:
try:
n = int(s)
except ValueError:
print("failed")
or similar.
Do you know the difference in meaning between isdigit, isnumeric, and
isdecimal?
> Anyway, I tried a
> try - except, but I don't see why my output is all integer when I only
> convert to integer if it passes the is_integer test:
That's what you *intended* to do, but it isn't what you did :-)
> user_values = []
> while True:
> user_input = input("Give me a number: ")
> if user_input.lower() == 'done': break
> try:
> user_input = float(user_input)
> if user_input.is_integer: user_input = int(user_input)
At the interactive interpreter:
py> x = 23.1
py> x.is_integer # no brackets
<built-in method is_integer of float object at 0xb7aef950>
py> x.is_integer() # with brackets
False
Built-in methods and functions are consider "truthy" values, so your
test user_input.is_integer (without the brackets) is always true and the
number will always be converted to an int.
Personally, I would not do the conversion like that. The big problem is
that for sufficiently large integers, floats lose precision:
py> s = '123456789012345678901'
py> int(s)
123456789012345678901
py> int(float(s))
123456789012345683968
Instead, I'd create a helper function that first tries to convert to an
int, and only if that fails, converts to a float:
def make_number(astring):
if not isinstance(astring, str):
raise TypeError('not a string')
for kind in (int, float):
try:
return kind(astring)
except ValueError:
pass
raise ValueError(
'String {0} is not a supported number.'.format(astring)
)
You could support more formats if you like, e.g. 0x123 for hex ints,
complex, fractions, percentages, whatever you wanted. But as a simpler
string-to-int-or-float function, this works well.
--
Steve
More information about the Tutor
mailing list