python – Asking the user for input until they give a valid response
python – Asking the user for input until they give a valid response
The simplest way to accomplish this is to put the input
method in a while loop. Use continue
when you get bad input, and break
out of the loop when youre satisfied.
When Your Input Might Raise an Exception
Use try
and except
to detect when the user enters data that cant be parsed.
while True:
try:
# Note: Python 2.x users should use raw_input, the equivalent of 3.xs input
age = int(input(Please enter your age: ))
except ValueError:
print(Sorry, I didnt understand that.)
#better try again... Return to the start of the loop
continue
else:
#age was successfully parsed!
#were ready to exit the loop.
break
if age >= 18:
print(You are able to vote in the United States!)
else:
print(You are not able to vote in the United States.)
Implementing Your Own Validation Rules
If you want to reject values that Python can successfully parse, you can add your own validation logic.
while True:
data = input(Please enter a loud message (must be all caps): )
if not data.isupper():
print(Sorry, your response was not loud enough.)
continue
else:
#were happy with the value given.
#were ready to exit the loop.
break
while True:
data = input(Pick an answer from A to D:)
if data.lower() not in (a, b, c, d):
print(Not an appropriate choice.)
else:
break
Combining Exception Handling and Custom Validation
Both of the above techniques can be combined into one loop.
while True:
try:
age = int(input(Please enter your age: ))
except ValueError:
print(Sorry, I didnt understand that.)
continue
if age < 0:
print(Sorry, your response must not be negative.)
continue
else:
#age was successfully parsed, and were happy with its value.
#were ready to exit the loop.
break
if age >= 18:
print(You are able to vote in the United States!)
else:
print(You are not able to vote in the United States.)
Encapsulating it All in a Function
If you need to ask your user for a lot of different values, it might be useful to put this code in a function, so you dont have to retype it every time.
def get_non_negative_int(prompt):
while True:
try:
value = int(input(prompt))
except ValueError:
print(Sorry, I didnt understand that.)
continue
if value < 0:
print(Sorry, your response must not be negative.)
continue
else:
break
return value
age = get_non_negative_int(Please enter your age: )
kids = get_non_negative_int(Please enter the number of children you have: )
salary = get_non_negative_int(Please enter your yearly earnings, in dollars: )
Putting It All Together
You can extend this idea to make a very generic input function:
def sanitised_input(prompt, type_=None, min_=None, max_=None, range_=None):
if min_ is not None and max_ is not None and max_ < min_:
raise ValueError(min_ must be less than or equal to max_.)
while True:
ui = input(prompt)
if type_ is not None:
try:
ui = type_(ui)
except ValueError:
print(Input type must be {0}..format(type_.__name__))
continue
if max_ is not None and ui > max_:
print(Input must be less than or equal to {0}..format(max_))
elif min_ is not None and ui < min_:
print(Input must be greater than or equal to {0}..format(min_))
elif range_ is not None and ui not in range_:
if isinstance(range_, range):
template = Input must be between {0.start} and {0.stop}.
print(template.format(range_))
else:
template = Input must be {0}.
if len(range_) == 1:
print(template.format(*range_))
else:
expected = or .join((
, .join(str(x) for x in range_[:-1]),
str(range_[-1])
))
print(template.format(expected))
else:
return ui
With usage such as:
age = sanitised_input(Enter your age: , int, 1, 101)
answer = sanitised_input(Enter your answer: , str.lower, range_=(a, b, c, d))
Common Pitfalls, and Why you Should Avoid Them
The Redundant Use of Redundant input
Statements
This method works but is generally considered poor style:
data = input(Please enter a loud message (must be all caps): )
while not data.isupper():
print(Sorry, your response was not loud enough.)
data = input(Please enter a loud message (must be all caps): )
It might look attractive initially because its shorter than the while True
method, but it violates the Dont Repeat Yourself principle of software development. This increases the likelihood of bugs in your system. What if you want to backport to 2.7 by changing input
to raw_input
, but accidentally change only the first input
above? Its a SyntaxError
just waiting to happen.
Recursion Will Blow Your Stack
If youve just learned about recursion, you might be tempted to use it in get_non_negative_int
so you can dispose of the while loop.
def get_non_negative_int(prompt):
try:
value = int(input(prompt))
except ValueError:
print(Sorry, I didnt understand that.)
return get_non_negative_int(prompt)
if value < 0:
print(Sorry, your response must not be negative.)
return get_non_negative_int(prompt)
else:
return value
This appears to work fine most of the time, but if the user enters invalid data enough times, the script will terminate with a RuntimeError: maximum recursion depth exceeded
. You may think no fool would make 1000 mistakes in a row, but youre underestimating the ingenuity of fools!
Why would you do a while True
and then break out of this loop while you can also just put your requirements in the while statement since all you want is to stop once you have the age?
age = None
while age is None:
input_value = input(Please enter your age: )
try:
# try and convert the string input to a number
age = int(input_value)
except ValueError:
# tell the user off
print({input} is not a number, please enter a number only.format(input=input_value))
if age >= 18:
print(You are able to vote in the United States!)
else:
print(You are not able to vote in the United States.)
This would result in the following:
Please enter your age: *potato*
potato is not a number, please enter a number only
Please enter your age: *5*
You are not able to vote in the United States.
this will work since age will never have a value that will not make sense and the code follows the logic of your business process
python – Asking the user for input until they give a valid response
Though the accepted answer is amazing. I would also like to share a quick hack for this problem. (This takes care of the negative age problem as well.)
f=lambda age: (age.isdigit() and ((int(age)>=18 and Can vote ) or Cannot vote)) or
f(input(invalid input. Try againnPlease enter your age: ))
print(f(input(Please enter your age: )))
P.S. This code is for python 3.x.