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
_______________________________________________
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
https://mail.python.org/mailman/listinfo/tutor

Reply via email to