[Tutor] How to handle a non integer within a question function that needs to return a integer?
Steven D'Aprano
steve at pearwood.info
Thu Mar 12 03:16:07 CET 2015
On Wed, Mar 11, 2015 at 09:26:38PM +0000, Wibble wrote:
[...]
> How do I make it show a message to users saying only numbers excepted
> and then the loop continues?
>
> I have tried this but same error is still generated.
>
> def user_choice(question, low, high, step = 1):
> """Define user choice"""
> choice = None
> while choice not in range(low, high, step):
> choice = int(input(question))
Your error occurs at the line above.
> if choice == str(input(question)):
> print('Numbers only please!')
And here you try to detect the error, but it's too late, since it has
already happened!
> return choice
>
> Do I need to create another while loop within this loop to handle a
> string input?
Yes you do, because the user might be stupid, clumsy, obnoxious, or a
cat walking on the keyboard, and might repeatedly type non-numbers. Or
they might innocently try typing number words like "one", "two", etc.
So let's break the question down. You want to give the user the option
to enter a number, then you want to check that it is within a range.
Let's start by accepting any old number:
# Python 3 version!
# for Python 2, make sure you use raw_input() not input()
def enter_number(prompt):
if not prompt.endswith(" "):
# Make sure there is at least one space between the prompt
# and where the user types.
prompt += " "
answer = input(prompt)
while not answer.isdigit():
print("You must enter a number!")
answer = input(prompt)
return int(answer)
If you try that, you will find a couple of limitations:
- it doesn't accept negative numbers;
- it doesn't accept floating point numbers like 1.2 or 3e5.
Here's another way to write the same function. It's a bit more verbose,
but probably a better design:
def enter_number(prompt):
"""Ask the user to enter an integer number.
Takes a single argument, the string to use to prompt the user.
This repeats until they enter an actual number.
"""
if not prompt.endswith(" "):
# Make sure there is at least one space between the prompt
# and where the user types.
prompt += " "
while True: # Loop forever.
answer = input(prompt) # use raw_input in Python 2
try:
number = int(answer)
except ValueError:
print("You must enter a number!")
else:
return number
This loops forever, asking the user for a number, then trying to convert
their answer into a number inside a `try` block. If the conversion
fails, the `except` block runs, and the loop continues. But if the
conversion succeeds, the `else` block runs, which returns the number,
thus breaking the infinite loop.
Now you can use that as a building block to write the function you want:
def user_choice(question, low, high, step = 1):
"""A better docstring would be appropriate."""
choice = None
while choice not in range(low, high, step):
choice = enter_number(question)
return choice
There's a problem with this function too -- if the user enters a number
out of range, they don't get any feedback as to why their answer is
rejected, instead they just get asked for a number again. Very
disheartening!
How about this?
def user_choice(question, num, high=None):
"""A better docstring would be appropriate."""
if high is None:
start = 1
end = num
else:
start = num
end = high
allowed = range(start, end+1)
while True:
choice = enter_number(question)
if choice in allowed:
return choice
else:
print("Out of range! Try again.")
--
Steve
More information about the Tutor
mailing list