Home > OS >  Strange Python try except behaviour with recursive function call
Strange Python try except behaviour with recursive function call

Time:07-24

The context: I am using the function get_quantity_input() to get user input and validate that it is an integer.

The problem: When I enter an invalid non-integer value (e.g. q) and subsequently enter a valid integer value (e.g. 2) the function returns the default value of -69. This is puzzling and only gets more puzzling when you inspect the output. I am sure there is something basic that I am misunderstanding. Any insights are greatly appreciated!

The functions:

def player_characters():
    pc_list = ['Dennis Le Menace', 'Pierre', 'Ronan', 'Dame Romaine']
    pcs = []
    for pc in pc_list:
        pc_init = get_quantity_input('{} initiative: '.format(pc))
        print(pc, pc_init)
        pc_dex_bonus = get_dex_bonus(pc)
        pcs.append(Character(pc, pc_init, pc_dex_bonus))
    return pcs

def get_quantity_input(something):
    num_of_something = -69
    try:
        num_of_something = int(input(something))
        print('inside try', num_of_something)
    except ValueError:
        print('Invalid input, please enter a number.')
        get_quantity_input(something)
    print('before return', num_of_something)
    return num_of_something

The output:

Dennis Le Menace initiative: q
Invalid input, please enter a number.
Dennis Le Menace initiative: 3
inside try 3        
before return 3 <-- why does this not get returned?!     
before return -69   
Dennis Le Menace -69
Pierre initiative: 12
inside try 12     
before return 12  
Pierre 12

CodePudding user response:

You need to return the result of your recursive call rather than just "falling through":

def get_quantity_input(something):
    num_of_something = -69
    try:
        num_of_something = int(input(something))
        print('inside try', num_of_something)
    except ValueError:
        print('Invalid input, please enter a number.')
        return get_quantity_input(something)  # <-- here
    print('before return', num_of_something)
    return num_of_something

I'd recommend simplifying the function down a bit by not declaring a default value that you never want to actually return -- as you have observed, this makes it easier to have mysterious bugs. If you want to do it recursively (which is not actually recommended) it would be more simply written as:

def get_quantity_input(something):
    try:
        return int(input(something))
    except ValueError:
        print('Invalid input, please enter a number.')
    return get_quantity_input(something)

If the try block succeeds, the function is done and the value is returned; if not, we just try the same thing again.

Because Python doesn't optimize recursion the way many languages do, using recursion for a loop is not recommended. (Specifically: most languages can do "tail call optimization" to handle arbitrarily deep recursion, provided that the result of the recursive call is to be returned immediately, by popping the stack before actually making the next recursive call, whereas Python will continue growing the stack and eventually raise an exception once it gets too deep.) Instead use while:

def get_quantity_input(something):
    while True:
        try:
            return int(input(something))
        except ValueError:
            print('Invalid input, please enter a number.')
  • Related