Search code examples
pythonuser-inputtext-based

Recursive function with same arguments


I'm creating a text-based game in python and have hit a road block. I have a function that checks if user input contains certain words, and if it does it returns the user-input, otherwise it will re-ask for the input. If you write something that doesn't contains one of the words, it will re-call the function.

def contains_words(prompt, words):

    user_input = raw_input(prompt).strip().lower()


    if user_input == "instructions":
        print
        instructions()
        print
        contains_words(prompt, words)

    elif user_input == "i" or user_input == "inventory":
        if len(inventory) == 0:
            print 
            print "There is nothing in your inventory."
            print
            contains_words(prompt, words)
        else:
            print "Your inventory contains: " + inventory
            contains_words(prompt, words)

    else:
        if user_input in words:
            return user_input
        else:
            print
            print "I did not understand your answer, consider rephrasing."
            contains_words(prompt , words) 

Here is me calling it:

pizza = contains_words("Do you like pizza?", ["yes", "no"])

Within this function you can bring up the instructions or your inventory and then it will recall the function. Everything works like normal if you put one of the words in your answer the first time you are asked. The problem happens when you enter something incorrect, bring up the inventory or bring up the instructions. It causes the function to return nothing, instead of user-input. Why is this happening? Is it because the function resets so the parameter equal none?


Solution

  • Let's walk through a sample call of this function.

    pizza = contains_words("Do you like pizza?", ["yes", "no"])
    

    Say the user inputs instructions. Your first if statement is True, so we enter that block, instructions() is called (presumably printing instructions to the console), and contains_words is called again. Let's say the user inputs yes this time. We'll get down to the last if statement, it'll be True, and this call of contains_words will return yes -- to where it was called.

    So, now we're back up the stack to the original call of contains_words. The return value is ignored, because the function is called on a line by itself and not as an argument to another function or statement. Now we're done with this if block, and the next thing in the function is ... nothing. The rest of the ifs. elifs and elses mean nothing (as the original if evaluated to True), and we drop out of the bottom of the function. It returns nothing (actually None). (Check the type of pizza to see.)

    The solution is to either change your recursive calls to return contains_words(prompt, words) so when the function drops out of each recursive call it passes the return value up the stack, or, since this is just tail-recursion anyway, replace it with a loop:

    def contains_words(prompt, words):
    
        while True:
            user_input = raw_input(prompt).strip().lower()
    
    
            if user_input == "instructions":
                print
                instructions()
                print
    
    
            elif user_input == "i" or user_input == "inventory":
                if len(inventory) == 0:
                    print 
                    print "There is nothing in your inventory."
                    print
                else:
                    print "Your inventory contains: " + inventory
    
            else:
                if user_input in words:
                    return user_input
                else:
                    print
                    print "I did not understand your answer, consider rephrasing."
    

    Which will avoid memory issues involved with potentially many recursions.