How did the While True loop end?

Project link: https://www.codecademy.com/journeys/computer-science/paths/cscj-22-intro-to-data-structures/tracks/cscj-22-queues-stacks-and-hashmaps/modules/cscj-22-python-stacks/projects/towers-of-hanoi

In this project there are two occasions that make use of While True loop.
From what I google, it is useful when we want to loop a condition and then explicitly break it when we are done.
However, consider below example - get_input function, there is no any break.
Why will the While True loop not loop forever?

def get_input():
  choices = []
  for stack in stacks:
    choices.append(stack.get_name()[0])
  
  while True:
    for i in range(len(stacks)):
      name = stacks[i].get_name()
      letter = choices[i]
      print("Enter {0} for {1}".format(letter, name))

    user_input = input("")

    if user_input in choices:
      for i in range(len(stacks)):
        if user_input == choices[i]:
          return stacks[i]

Thanks!

It will loop forever unless the user provides an input that matches one of the valid choices.

When such an input is provided, the condition

if user_input in choices:

will be true, and

return stacks[i]

will return from the function causing the while loop to be exited.

If user_input is not one of the valid choices, then the while loop will keep looping until a valid input is provided.

1 Like

The return leaves the function.

You can move that return to the bottom with something like:

def get_input(stacks):
    choices = []
    for stack in stacks:
        choices.append(stack.get_name()[0])
  
    pick = -1
    while pick == -1:
        for i in range(len(stacks)):
            name = stacks[i].get_name()
            letter = choices[i]
            print("Enter {0} for {1}".format(letter, name))
        user_input = input("")

        if user_input in choices:
            for i in range(len(stacks)):
                if user_input == choices[i]:
                    pick = i
                    break # found it, leave
    return stacks[pick]

Now, jumping out of a function with a return does make sense for this kind of thing. I’d generalize this a little:

def input_choice(choices):
    while True:
        for name in choices:
            print("Enter {0} for {1}".format(name[0], name))
        user_input = input("")

        # hate doing this twice 
        # if user_input in choices:
        for i in range(len(choices)):
            if user_input == choices[i][0]:
                return i

Once you write this function you can apply it anywhere you need such logic. The prior function could leverage it like this:

def get_input(stacks):
    choices = []
    for stack in stacks:
        choices.append(stack.get_name())
    return stacks[input_choice(choices)]

Or, if you’ve covered comprehensions:

def get_input(stacks):
    return stacks[input_choice(stack.get_name() for stack in stacks)]
1 Like