0
def my_function():
    try:
        number = int(input("What is your favorite number?\n\n"))
    except ValueError: #if anything but an integer was given as the str to input
        my_function() #recursive to ask again
    return number
my_function()

This throws the exception UnboundLocalError: local variable 'number' referenced before assignment if I go through the recursive scope at least once and then give a valid input. I thought the variable number should point to a different object every iteration of the function. What am I missing here?

I recognize I can simply move return number into the try block to achieve this functionality, but why do I have to?

James Carter
  • 803
  • 2
  • 10
  • 18
  • 3
    Use `return my_function()` in the exception clause and things may work better. With that in mind, (re)read Karl's comment. – 9769953 Apr 25 '21 at 21:36

1 Answers1

3

I thought the variable number should point to a different object every iteration of the function.

What causes the local variable number to get set in the current call? Answer: number = int(input("What is your favorite number?\n\n")). Does it always get assigned? Answer: No, not if int raises an exception. When does the recursive call happen? Answer: when, and only when, the exception is raised. Therefore, when a recursive call happens, does number have a value set in the current call? Answer: No.

I recognize I can simply move return number into the try block to achieve this functionality

No; this does not work! If the exception is raised, then return number does not happen in the current call. The recursive call will occur, and then the value returned from that recursive call will be ignored. In the current call, control flow reaches the end of the function, and None is returned. You would have to explicitly return the value from the recursive call, or explicitly assign it to number and then return that afterward.

But that's ugly. You should just use a loop for this, like everyone else does.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • Great explanation for something quite counterintuitive to me. Thank you! – James Carter Apr 25 '21 at 21:52
  • The golden rule for understanding recursion: imagine the recursive call is to a *different* function that somehow magically does what you want the recursive call to do (complete black box), and then consider the logic normally. – Karl Knechtel Apr 25 '21 at 21:53
  • Yeah that;s exactly where my understanding was lacking. Before I thought a recursive call is an extension of one function, not a new "nested" function call. I see it properly now, thank you! – James Carter Apr 26 '21 at 15:28
  • Yep. Again, it's the same as a non-recursive call, except for the recursiveness. ;) – Karl Knechtel Apr 26 '21 at 21:06