2

I'm fairly new to python (coding in general really), but I mostly grasp what's put in front of me. I'm trying to create an input that will only accept integers, so I put together the following function:

def askFor(request):
   """Program asks for input, continues to ask until an integer is given"""
   num = ' '
    while (isinstance(num, int) == False):
        num = input(request)
    else:
        return num

it works fine when i enter a number, but anything else breaks it instead of looping it back. Am I missing an element, or am I just best off to go with

str(input('wargharble: '))
DJ80
  • 43
  • 1
  • 1
  • 8
  • 5
    Just a stylistic note: `while not isinstance(num, int):` is a little more Pythonic than `while (isinstance(num, int) == False):`. :) – Pieter Witvoet Jan 05 '13 at 05:30
  • The problem is that in Python 2 `input()` runs `eval()` on whatever the user types in (see the [docs](http://docs.python.org/2/library/functions.html?highlight=input#input)), so if it's not valid Python syntax for a constant or literal expression, like `42`, `1+2`, or `"Bob"`, an exception will be raised which your program will need to catch. I suggest you instead use `num = int(raw_input(request))` within a `try/except` clause because it doesn't use `eval()` and is therefore safer. – martineau Jan 05 '13 at 14:12

5 Answers5

4

You are on the safer side with raw_input in Python 2, because it will always return a string, whereas input will try to evaluate the given string, which is dangerous.

def askFor(prompt):
    """ ask for input, continues to ask until an integer is given
    """
    number = None
    while True:
        try:
            number = int(raw_input(prompt))
            break
        except ValueError:
            pass # or display some hint ...
    print(number) # or return or what you need ...
miku
  • 181,842
  • 47
  • 306
  • 310
  • I was just in the middle of writing the exact same thing! But anyway, you might consider mentioning that in python 2 `input` evaluates the input as python code, while `raw_input` returns a string. – Volatility Jan 05 '13 at 05:24
  • @Volatility, *you might consider mentioning ...*: my thought exactly :) – miku Jan 05 '13 at 05:24
  • this didn't seem to work with the rest of the code that I had. Whenever I entered a non-integer, it would accept it, and not ask for the same data again, then break when it's line came up. – DJ80 Jan 05 '13 at 05:58
  • @DJ80, the snippet works for me as it is posted here - it asks for input as long as the user does not input an int. – miku Jan 05 '13 at 06:00
  • @Miku, I've copy/pasted your coding to a new file with the rest of my program, and it now functions as you said. I likely just missed something simple like changing input to raw_input. Now I just need to wrap my brain around what makes it work. – DJ80 Jan 05 '13 at 06:16
0

This is because input() is failing on non-integer input (this has to do with the fact that input() is calling eval() on the string your inputting (see python builtins).

raw_input() does not. (in fact, input() calls raw_input())

Try this instead:

while True:
    num = raw_input(request)
    if num.isdigit():
        break

The isdigit() function checks to see if each character in a string is a digit ('0' - '9')

eqzx
  • 5,323
  • 4
  • 37
  • 54
0

The problem is that input() returns the raw user input evaluated as a python expression. So when you input something like "someinput" on the console here is what happens:

  1. The raw input is captured from the console as a string
  2. That string is then parsed as a python expression (so imagine you simply type this string into your program, in this case, it becomes a variable with the name "someinput"
  3. When isinstance() is called on this python expression, the python interpreter can't find a variable named "someinput" which is defined - so it throws an exception.

What you really want to do is use raw_input(), this will return a string representing the user's input. Since you are receiving a string from the console now though, you need some way of checking if a string is an int (because isinstance will always return a string)

Now to determine if the string is a number, you could use something like isdigit() - but be careful - this function will validate any string that contains only digits (so 0393 would be valid).

Here are the corrections that need to be made:

def askFor(request):
   """Program asks for input, continues to ask until an integer is given"""
   num = ' '
    while (num.isdigit() == False):
        num = raw_input(request)
    else:
        return num
Will C.
  • 599
  • 3
  • 8
0

Well first off, your indentation if a bit off (the while loop's indentation level does not match the previous level).

def askFor(request):
    """Program asks for input, continues to ask until an integer is given"""
    num, isNum = '', False # multiple assignment
    while not isNum:
        num = input(request)
        if type(num) in (int, long): # if it is any of these
           isNum = True
           break  
        else: isNum = False
    return num # at the end of the loop, it will return the number, no need for an else

Another way to do it:

def askFor(request):
    """Program asks for input, continues to ask until an integer is given"""
    num, isNum = '', False
    while not isNum:
        num = raw_input(request)
        try: # try to convert it to an integer, unless there is an error
            num = int(num)
            isNum = True
            break
        except ValueError:
            isNum = False
    return num
Rushy Panchal
  • 16,979
  • 16
  • 61
  • 94
  • *-1*: In you first snippet you use `type`, which is a kind of last resort, if nothing else works (see also: http://stackoverflow.com/a/1549854/89391); in your second example you introduce too much clutter. – miku Jan 05 '13 at 05:46
  • The first way didn't work for me, but the second way seems to work perfectly. I see I need to read up more on try statements. Many thanks. – DJ80 Jan 05 '13 at 05:59
  • Yeah the problem with the first one is that say the user enters 'two' for the `input` statement, `two` is used as a variable. As it is not defined, you will get a `NameError`. You could use `try` and `except` with that as well, or use `raw_input`; `raw_input` returns the user's input as a string, so then you can use a `try` to convert it to an integer, unless there is an error (most likely `TypeError`); then prompt them again. – Rushy Panchal Jan 06 '13 at 18:57
0

input evaluates whatever's typed in as Python code, so if the user types something non-sensical in, it'll produce an error. Or worse, it can run arbitrary commands on your computer. Usually, you want to use raw_input and convert the string value it returns safely yourself. Here, you just need to call int on the string, which can still produce an error if the user enters a non-int, but we can handle that by looping.

And voila:

def read_int(request):
    while True:
        try:
            return int(raw_input(request))
        except ValueError:
            pass

Note, there's no need for break or else; just return the value once you have parsed it successfully!

Paul Hankin
  • 54,811
  • 11
  • 92
  • 118