CinnamonRii
CinnamonRii

Reputation: 156

What happens if you return a function recursively and is this good practice?

I've written this small random number guessing game as part of my study about Python. My question is, what happens if I return a function by itself? Is this considered good practice? Does this cause some sort of buffer or stack overflow? (no pun intended)

I really haven't found a clear answer, not even for other languages.

If anyone wants to ask why, I did this because I wanted to loop the program until the user types 'exit'.

# Simple guess the random number game

# Import this module for generating a random number
import random 

# Function to determine if answer is too low, too high, or if it is correct
def guessFunc(guessInput, randomNum):
    if guessInput < randomNum:
        return 'The number is too low'
    elif guessInput > randomNum:
        return 'The number is too high.'
    else:
        return 'Correct!'

# Function that checks if user input is valid.
def checkValid_Input(userInput):
    if userInput.isdigit():
        return True

    return False

# The "main" function of the whole game
def mainFunc():
    userGuess = ''
    guessResult = ''
    secretNum = random.randint(0, 20) #Generate random number
    tries = 0

    # Game loop, the program ends if user types 'Exit'/'exit'.
    while True:
        print('I\'m thinking of a number between 0 and 20...')
        userGuess = input()

        # Check first if user typed 'exit'. If true, terminates the program
        # if False, continues code execution.
        if str.lower(userGuess) == 'exit':
            return

        # If the previous condition is false, perform this method.
        # This checks if user input is valid.
        isValid = checkValid_Input(userGuess)

        if isValid == False:
            print('Invalid input, please try again.\n')
        else:
            guessResult = guessFunc(int(userGuess), secretNum)
            tries = tries + 1
            print(guessResult + '\n')

            if tries == 6 and guessResult != 'Correct!':
                print('Nope, the secret number is: ' + str(secretNum))
                print('Press any key to continue')
                _ = input()
                return mainFunc()

            if tries <=6 and guessResult == 'Correct!':
                print('It took you ' + str(tries) + ' tries to get it.')
                print('Press any key to continue')
                _ = input()
                return mainFunc()

# Initialize/call main function       
mainFunc()

Upvotes: 1

Views: 74

Answers (1)

Scott
Scott

Reputation: 377

Just to clear things up a little, I stripped this problem down to the bare minimum needed to get some output and traceback. I placed the code in test1.py.

Note that nothing within mainFunc() causes even a gradual change leading towards an eventual exit condition so all it does is increment a counter and print the new value before reaching the return statement:

count = 0
def mainFunc():
    global count
    count += 1
    print('count:',count)
    return mainFunc()

mainFunc()

This caused Python to execute 1012 print statements producing the following (highly abbreviated) output:

count: 1
count: 2
...
count: 1012

...at which point it failed with the following Traceback:

Traceback (most recent call last):
  File "C:\MyPython\Code\test1.py", line 9, in <module>
    mainFunc()
  File "C:\MyPython\Code\test1.py", line 6, in mainFunc
    return mainFunc()
  File "C:\MyPython\Code\test1.py", line 6, in mainFunc
    return mainFunc()
  File "C:\MyPython\Code\test1.py", line 6, in mainFunc
    return mainFunc()
  [Previous line repeated 1009 more times]
  File "C:\MyPython\Code\test1.py", line 5, in mainFunc
    print('count:',count)
RecursionError: maximum recursion depth exceeded while pickling an object

This makes sense because each time the return mainFunc() statement was reached, it invoked mainFunc() in order to determine what value to return to the caller (which was implicitly __main()__ the very first call, and mainFunc() itself recursively thereafter).

The Traceback supports our general consensus that it is indeed recursion, and that recursion does have a (default) limit.

Finally, to answer the question is this good practice?:

Sometimes yes and sometimes no - I can think of a VERY common application suited to recursive design:

Factorials, where factorial(n) should return the output of the calculation of 3 x 2 x 1 = 6, where n=3. The exit condition would be that each subsequent call invokes factorial(n-1) so the parameter passed progressively decrements towards an exit condition within the function.

In order to recurse there must be an exit condition or the endless loop will eventually cause a RecursionError.

Upvotes: 1

Related Questions