[Tutor] Python-list thread: int vs. float

Steven D'Aprano steve at pearwood.info
Sat Feb 11 03:06:07 EST 2017


On Fri, Feb 10, 2017 at 07:59:04PM -0600, boB Stepp wrote:

> He cannot figure out how to reliably tell if the user's input is an
> integer, float or neither.  So I thought I would come up with my
> solution, which currently is:
> 
> py3: def ck_input():
> ...     value_to_ck = input('Enter a number:')
> ...     try:
> ...             value = int(value_to_ck)
> ...             print('You have entered an integer.')
> ...     except ValueError:
> ...             try:
> ...                     value = float(value_to_ck)
> ...                     print('You have entered a float.')
> ...             except ValueError:
> ...                     print('You have failed to enter a numerical value.')
> ...
[...]
> This is all well and good.  I am not trying to elicit an "Atta boy,
> boB!" here. ~(:>)) 

Nevertheless, atta boy boB! 

The only not-so-good part of this is that you have mixed user-interface 
and internal calculation. Better:


def to_number(string):
    """Convert string to either an int or a float, or raise ValueError."""
    try:
        return int(string)
    except ValueError:
        return float(string)


def check_input():
    value_to_ck = input('Enter a number: ')
    try:
        value = to_number(value_to_ck)
    except ValueError:
        print('You have failed to enter a numerical value.')
        return
    if isinstance(value, float):
        print('You have entered a float.')
    else:
        print('You have entered an int.')


This gives you nice separation between the function that interacts with 
the user, and the function that does the actual conversion.



> Instead, I am wondering if there is something in
> Python's wonderful cornucopia of programming stuff that can simplify
> this type of check.

The most reliable and foolproof way of checking if something is a valid 
int is to ask int to convert it, and see if it fails.

Likewise for floats, where the format is *very* complex. Any of these, 
and many more, should be accepted:

    1.2345
    +1.2345
    -1.2345e0
    123.45e+20
    123.45E-20
    .123
    -.123
    +.123e-12
    123.
    inf
    +inf
    -inf
    NaN

Getting all the gory details right of what is and isn't allowed may be 
tricky, but that's okay, because float() already understands how to do 
it for you.


> As you might guess from my earlier post this
> evening, I have been playing around with "type()" and "isinstance()",
> but if I try something like:
> 
> py3: isinstance(int('5.0'))
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
> ValueError: invalid literal for int() with base 10: '5.0'

The problem here is that int('5.0') raises an exception because '.' is 
not a valid digit for integers, so it fails before isinstance() gets a 
chance to run.

Valid digits for integers include 0 through 9 in decimal, plus no more 
than one leading + or - sign, and whitespace (space, tabs, newlines) 
before or after the string. If you specify the base, the set of valid 
digits will change, e.g. int(string, 16) will allow 0 through 9 plus A 
through F in lower and upper case.

But whatever base you choose, '.' is not a valid digit.



-- 
Steve


More information about the Tutor mailing list