Search code examples
pythontry-except

Scope of a try/except block


I know that try/except blocks do not have separate scopes, and I also know the actual solution to this problem, though I want to know why it happens. I am making a simple guessing game for my sdev class and while I can just add guess_num before the try/except block to make it work, why do I have too?

I have it loop back to main, but if I go through the program and do not enter a number as input, it eventually brings me back to the input again, but if I then do a number, it will give me this error:

Traceback (most recent call last):
  File "C:\Users\Jexxy\Documents\MyRepo\Guessing_Game.py", line 35, in <module>
    main()
  File "C:\Users\Jexxy\Documents\MyRepo\Guessing_Game.py", line 31, in main
    if guess_num > 0 and guess_num < 100 and isinstance(guess_num, int):
UnboundLocalError: local variable 'guess_num' referenced before assignment
def main():
    random_num = random.randrange(1, 5)
    try:
        guess_num = int(input('''Welcome to the guessing game!
                 A Random number between 1-100 has already been generated!
                 When ready, please enter a number between 1-100 to make your guess: '''))
    except ValueError:
        try_again = input("You must enter a number! Try again? Y/N: ")
        if try_again.lower() == "y":
            main()
        else:
            exit(0)

    if guess_num > 0 and guess_num < 100 and isinstance(guess_num, int):
        print(guess_num)

Solution

  • guess_num is only set if input() or int() succeeded. If either of those throws an exception, Python doesn't have a value to assign to guess_num.

    Your real mistake is to use recursion however. When you handle the exception, you call main() again. Eventually, main() returns and the code continues from the point where you called main(). Each recursive call to main() has their own set of local variables, so by the time main() returns, all successful runs of main() are gone, taking their local variables with them. Even if guess_num was set in one of the recursive calls, it doesn't survive to live in a parent function run.

    So what really happens is this:

    1. you enter a non-integer value, and an exception is raised
    2. you call main(), and run your code successfully this time.
    3. main() returns, and now you try to access the local variable guess_num, but it was never set.

    Don't use recursion. Use a loop. Or, if you must use recursion, Use return main(), so the function exits once the recursive call to main() ends.