Python Forum
Validating User Input - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: General (https://python-forum.io/forum-1.html)
+--- Forum: Tutorials (https://python-forum.io/forum-4.html)
+---- Forum: Fundamentals (https://python-forum.io/forum-40.html)
+---- Thread: Validating User Input (/thread-18971.html)



Validating User Input - ichabod801 - Jun-08-2019

A common task in computer programming is to validate user input. We don't just want to get user input, we want to make sure that input is the correct type of input. By checking the user's input before processing it, we can avoid errors further on in the program. This is a type of "defensive programming," where you anticipate problems and handle them before they can make your program crash.

So how are we going to do this? First we should ask the question. Then we check the input, and return it if it is valid. If it is not valid, we should tell the user that it is not valid, and then ask the question again. In other words, we want to keep asking the question until we get a correct answer. If we are doing something over and over again, we will want a loop. If we want to do it until we get a correct answer, that means we want to break out of the loop when we get the correct answer.

So our general format is going to look like this:

while True:
    answer = input('Enter something: ')
    if valid(answer):
        break
    print('That is not valid.')
Line by line:
  • while True loops until a break statement.
  • We use input to get a potential answer from the user.
  • We use an if statement that checks the validity of the answer.
  • If the answer is valid, we break out of the loop.
  • Otherwise, we inform the user of their error.

Often we want an answer from a limited set of choices. Applying that to our general format might give us this code:

food = ['pizza', 'burgers', 'sushi']
while True:
    answer = input('Would you like to get pizza, burgers, or sushi? ')
    if answer.lower() in food:
        break
    print("I don't know of a {} restaurant near here.".format(answer))
print("Okay, let's have {}.".format(answer))
A sample run of this code might look like this:

Output:
Would you like to get pizza, burgers, or sushi? fried chicken I don't know of a fried chicken restaurant near here. Would you like to get pizza, burgers, or sushi? crottled greep I don't know of a crottled greep restaurant near here. Would you like to get pizza, burgers, or sushi? Pizza Okay, let's have Pizza.
Another common task is to get a number. Say we want to get an integer from the user. We might try this code:

while True:
    text = input('Please enter an integer: ')
    if text.isdigit():
        number = int(text)
        break
    print('{} is not an integer.'.format(text))
print((number + 1) * 2)
The isdigit method of a string makes sure that all of the character in the string are digits. If they are all digits, the text will convert to an integer.

Here's a sample run of the integer validation code:

Output:
Please enter an integer: Fred Fred is not an integer. Please enter an integer: -2 -2 is not an integer. Please enter an integer: 801 1602
Now, obviously Fred is not an integer. It may not be polite to say this about Fred, but it is unfortunately true. The problem is that -2 is an integer, but our code doesn't realize that. That's because the negative sign (-) isn't a digit. We could maybe modify our code to check for an initial dash, but then what if we want a floating point number? Our if statement is starting to get rather complicated. We could use regular expressions (the re module) to simplify this, but sometimes it's better to just try to do the conversion we want. If there is no error, we break out of the loop. If there is an error we keep asking the question. We do this with a try/except block, like this:

while True:
    text = input('Please enter a number: ')
    try:
        number = float(text)
        break
    except ValueError:
        print('{} is not a number.'.format(text))
print((number + 1) * 2)
If you are not familiar with try/except, it is used to catch errors. If the code indented under the try statement causes an error, the except statement is checked. If the error matches what is listed in the except statement, the code there is executed (in this case printing a warning about invalid input). Note that if our conversion to float causes an error, the code goes straight to the except statement, bypassing the break statement. If it doesn't cause an error, than the break statement is executed, and we get out of the while loop.

Note that you can do a lot more with a try statement than what I've shown here. If you are not familiar with the try statement, you should research it.

Here's a sample run using try/except:

Output:
Please enter a number: Fred Fred is not a number. Please enter a number: -2.71828 -3.43656
Now the code recognizes not only a negative number, but one with a decimal point.

But it may not be that simple. We may need to check that the number is in a certain range. To do this we combine the two pieces we used so far. We use try/except to make sure we have a number, and then we use an if statement to make sure we have the kind of number we want.

Say we have a number guessing game, and we need the user to guess a number from 1 to 100. Here's how we would do it:

while True:
    text = input('Guess a number from 1 to 100: ')
    try:
        number = int(text)
    except ValueError:
        print('{} is not a number.'.format(text))
        continue
    if number < 1:
        print('{} is too low.'.format(number))
    elif number > 100:
        print('{} is too high.'.format(number))
    else:
        break
print('You guessed {}.'.format(number))
Note that the try block is a bit different. Before I let the code continue to a break statement if the number conversion did not raise an error. Here, I instead have the except clause use a continute statement (which skips back to the top of the loop). I could have put the if/elif/else section under the try statement, like I did with the previous break statement. However, you should try to keep as little code as possible under the try statement. This is because you might get a ValueError in the if/elif/else section, and the code in the except block might not be appropriate for this other ValueError. The use of the continue statement allows us to move the if/elif/else code outside the try block. We still need a break statement or the while loop will continue forever, so we put that in the else clause. The else clause only executes if our number meets both of the conditions we have set for it (being at least 1 and no more than 100).

Here's a simple run of the combined testing:

Output:
Guess a number from 1 to 100: Fred Fred is not a number. Guess a number from 1 to 100: 3.14159 3.14159 is not a number. Guess a number from 1 to 100: -17 -17 is too low. Guess a number from 1 to 100: 801 801 is too high. Guess a number from 1 to 100: 23 You guessed 23.
Poor Fred, still not a number. Now, pi is a number, but we're looking for an integer. This was not a mistake on my part, but rather an intentional lesson on having clear error messages. If we enter integers that are not between 1 and 100, we do get clear error messages, so that is nice.

Hopefully you now understand how to use while loops with various test methods to get the correct input from your users. This is very important in computer programming, because nothing will mess up your code worse than an actual user.