'Python: Function is looping the amount of times there is incorrect input

I'm trying to check the input provided by the user to ensure that they enter a positive integer. However, when I test the code it loops the next line of the function its nested in the amount of times there was an error. I'm new to this so all help is appreciated.

This is the function that checks the input.

def check_input(a, b, c, d):
    global checked
    try:
        a = int(a)
        if b == how_many_get_on or b == how_many_get_off:
            if a < 0:
                print (str(c) + " Please enter a positive integer.")
                print("!1")
                b();
            else:
                d = True
                return d
        elif a < 1:
            print(str(c) + " Please enter a positive integer.")
            print("!2")
            b();
    except ValueError:
        try:
            a = float(a)
            print(str(c) + " Please enter a positive integer.")
            print("!3")
            b();
        except ValueError:
            print(str(c) + " Please enter a positive integer.")
            print("!4")
            b();

The following is the code that it's nested in. When the user inputs "ok", -10 and then 100 it will execute on the correct input however the output of the print statement is:

False
False
Flase

def how_many_get_on():
    global passengers, happy, unhappy, num_stops, limit, mount, checked
    checked = False
    waiting_statement = "How many passengers were waiting for the bus at stop #" + str(stop_num) + "? ";
    mount = input(waiting_statement);
    check_input(mount, how_many_get_on, "Invalid number of passengers.", checked)
    print(checked)
    while checked == True:
        waiting_statement = "How many passengers were waiting for the bus at stop #" + str(stop_num) + "? ";
        mount = input(waiting_statement);
        check_input(mount, how_many_get_on, "Invalid number of passengers.")
        print("again")
        if int(mount) >= 0 and stop_num < int(num_stops):
            if (passengers + int(mount)) <= limit:
                passengers += int(mount)
                happy += int(mount)
                print("Passengers: " + str(passengers))
                print("happy: " + str(happy))
                print("unhappy: " + str(unhappy))
                return
            elif (passengers + int(mount)) > limit:
                free_space = limit - passengers
                passengers += free_space
                left_over = int(mount) - free_space
                happy += free_space
                unhappy += left_over;
                print("Passengers: " + str(passengers))
                print("happy: " + str(happy))
                print("unhappy: " + str(unhappy))
                return

There are lots of print statements in as I was trying to track the source of the issue, and the code is super clunky but any help with this iteration problem is much appreciated.



Solution 1:[1]

You created a recursion, probably unintentionally:

In your check_input whenever you get an error, you call how_many_get_on (lines where b() is written).

I suspect you think this will return you somehow to how_many_get_on but that is not what is happening!

Instead, another copy of how_many_get_on is run, but then assuming there is no error in input, your old check_input exits, and the old how_many_get_on with the bad input resumes.

Here is how the call stack for your sample input:

how_many_get_on("OK") <-
     |                  |
      --> check_input("OK") <------
             |                     |
              --> how_many_get_on(-100) <-
                      |                   |
                       --> check_input(-100) <----
                             |                    |
                              --> how_many_get_on(10) <----
                                    |                      |
                                     ---> check_input(10) -

See the loop of calls?

Your how_many_get_on still resumes for every wrong input.

The proper design would be something like this:

def check_input(number):
    ... some code that checks number ...
    if input is bad:
        return False

    return True


def how_many_get_on():
    ...some code...

    mount = input(waiting_statement)

    while not check_input(mount)
        mount = input(waiting_statement)
    
    ...rest of the code...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Lev M.