0

New to Python, I wanted to create a function that prompts the user for input and checks if it's an acceptable input (there's a list of ok inputs). If acceptable - returns the input. If not - prompts the user again until he provides an acceptable input.

This is what I used:

def get_choice():
possible_choices = ["option1","option2","option3","option4"]
choice = raw_input("Please enter your choice: ").lower()
if choice not in possible_choices:
    print "Sorry, please try again"
    return get_choice()           # if not an acceptable answer - run the function again                     

return choice

now, this works. What I'm wondering about is the return command when the if condition is True. Intuitively I didn't place return there, just called the function again, and it would indeed run it again if the user didn't input an acceptable entry. However, the function itself would return the original value the user inputted, acceptable or not. Only when I added return before calling the function again, it started to work fine.

Can anyone explain why that is? It 'makes sense' that when calling the function again, choice would now point to the new user input, not the first one.

I got the idea to add the return there from Abrixas2's answer to this question:
Python getting user input errors.

However, over here: Continually prompting user for input in Python, part of audionautics's answer relates to a similar issue and he suggests this function:

def get_input_number():
    num = int(raw_input("Enter a positive integer no greater than 42 "))
    if num <= 0 or num > 42:
        print "Invalid input.  Try again "
        get_input_number()
    else: 
        return num

Obviously the input needs to be validated by other criteria than me, but you get that the nature of the problem is the same. He doesn't have a return statement there before calling the function again. I tried running this code along with:

test = get_input_number()
print test

to print the result, and it returned nothing. The reason I bring it up is that it still got 3 upvotes (most upvotes for that question) so I didn't want to dismiss it all together when I'm researching this issue.

Anyway, bottom line, can someone please explain what's the right way to go about it and why did my function without the return statement inside the if condition returned the first value the user inputted?

Thanks :D

Community
  • 1
  • 1
Optimesh
  • 2,667
  • 6
  • 22
  • 22

1 Answers1

2

You are using recursion; you are calling the function itself again. Each function call has it's own independent names; the recursive call gets a new choice variable, the one in the current body won't change.

if choice not in possible_choices:
    print "Sorry, please try again"
    return get_choice()

That function recursive call returns something, and if you didn't return whatever the recursive call returned, you'd ignore it; whatever the nested get_choice() returned would be for nothing.

The choice variable set before that call would still be the old, wrong value, as it is independent of the choice value in recursive calls.

You could also do:

if choice not in possible_choices:
    print "Sorry, please try again"
    choice = get_choice()

return choice

e.g. set the current choice to the return value, so the local choice would now reflect what the recursive call returned.

You shouldn't use recursion to ask for user input, however. Use a loop instead. A loop can go on indefinitely, while recursive calls will run out of stack space eventually. A stubborn user would break your program otherwise:

def get_choice():
    while True:
        possible_choices = ["option1","option2","option3","option4"]
        choice = raw_input("Please enter your choice: ").lower()
        if choice in possible_choices:
            return choice
        print "Sorry, please try again"

Here the return will end the loop, exiting the function. If you don't return, the loop just keeps on going, and the user will have to make a correct choice.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thanks a lot! :) I think I better understand (hard to visualize the process), and the alternative you suggested is elegant and nice :) So, is the answer from another I quoted and referred to just wrong, or are there cases that would hold? It doesn't appear so, but still wondering how it got upvotes if it's not correct. – Optimesh Mar 01 '14 at 11:49
  • I'm not certain where the recursion pattern for user input has sprung from. The posts you refer to don't have that many upvotes; they do address the question, and other answers on the pages you linked to do use loops instead of recursion. – Martijn Pieters Mar 01 '14 at 11:57
  • 1
    In other words, the votes are on those posts because the answers were deemed helpful to some, but that doesn't necessarily validate the technique. There are a **lot** of posts on user input here on Stack Overflow, so voting on these kinds of answers is also rather diluted. – Martijn Pieters Mar 01 '14 at 11:59