Home > Net >  Unexpected behavior in a nested while loop
Unexpected behavior in a nested while loop

Time:12-01

I'm trying to better understand how Python flow control works. Accordingly, I wrote a little script to understand how to make functional menus that include the ability to enter and leave sub-menus. The code below works as expected (no errors, it prints the expected output, etc). But when I enter option 4 "Exit" in the sub-menu "stage1" it accepts the input and re-prints the sub-menu. If I select option 4 again it exits the sub-menu and returns me to the main menu.

Why would it work after selecting the option twice?

I trimmed my code down to include the snippet for your review, and once I trimmed it down, it no longer requires I enter the "Exit" option twice. I'd like to have a menu with more than 1 option, so I'd love to get to the bottom of this.

import time
import os

def stage1():
    print("stage1")
    time.sleep(1)
    stage1_loop = 1
    while stage1_loop == 1:
        os.system('clear')
        print("Sub Menu")
        print("1. Stage 1")
        print("4. Exit")
        option = int(input("Please select a stage."))
        if option == 1:
            stage1()
        elif option == 2:
            stage2()
        elif option == 3:
            stage3()
        elif option == 4:
            print("Exit")
            stage1_loop = 0

main_loop = 1
while main_loop == 1:
    os.system('clear')
    print("Main Menu")
    print("1. Stage 1")
    print("4. Exit")
    option = int(input("Please select a stage."))
    if option == 1:
        stage1()
    elif option == 2:
        stage2()
    elif option == 3:
        stage3()
    elif option == 4:
        print("Exit")
        main_loop = 0

If I comment out the elif lines for stage 2 & 3 in the sub-menu then the issue disappears.

CodePudding user response:

I see multiple potential issues here, let's get into it:

  • First issue: stage1 is recursive:

You've included a call to stage 1 inside stage 1. Which means that when you call the stage1 function if you press 1, you have created a sub-sub menu.

To fix this issue is suggest the following edit:

def stage1():
    print("stage1")
    time.sleep(1)
    stage1_loop = 1
    while stage1_loop == 1:
        os.system('clear')
        print("Sub Menu")
        print("1. Stage 1")
        print("4. Exit")
        option = int(input("Please select a stage."))
        if option == 1:
            continue  # This skips to the next loop iteration
        elif option == 2:
            stage2()
        elif option == 3:
            stage3()
        elif option == 4:
            print("Exit")
            stage1_loop = 0
  • Second issue: You'd like for exit to quit, but you are inside a sub menu.

For that simply call the exit() method and your code will terminate altogether. You won't need to exit the submenu and then the menu.

Note: I may have misunderstood this last point, in that case simply ignore the second issue.

CodePudding user response:

Your code is quite messy:

  • You don't require to create variables for while. You can use True and break
  • Looks like you're repeating code a lot of times, we'll fix that later on

Here's the fixed code:

import time
import os

def stage1():
    print("stage1")
    time.sleep(1)
    while True:
        # os.system('clear')
        print("Sub Menu")
        print("1. Stage 1")
        print("4. Exit")
        option = int(input("Please select a stage."))
        if option == 1:
            stage1()
        elif option == 2:
            stage2()
        elif option == 3:
            stage3()
        elif option == 4:
            print("Exit")
            return True # returns true and exits the loop

while True:
    # os.system('clear')
    print("Main Menu")
    print("1. Stage 1")
    print("4. Exit")
    option = int(input("Please select a stage."))
    if option == 1:
        if stage1(): # checks if stage 4 is True and then breaks the loop
            break
    elif option == 2:
        stage2()
    elif option == 3:
        stage3()
    elif option == 4:
        print("Exit")
        break

Here's a faster non-repeating code for all 4 stages:

import time
import os

def stageFunction(stage):
    if stage in [1,2,3]: print(f"Stage {stage}") # Fast print stage number
    if stage == 1:
        # Do whatever
        pass
    elif stage == 2:
        # DO whatever
        pass
    elif stage == 3:
        # Do whatever
        pass
    elif stage == 4:
        print("Exit")
        # Do whatever
        exit()
    else:
        print("Invalid Stage!")

def stageSystem(stage=0):
    # os.system('clear')
    print("Main Menu")
    for i in range(1,4):
        print(f"{i}. Stage {i}") # fast print stages
    print("4. Exit")
    option = stage
    if (not stage): 
        option = int(input("Please select a stage: "))
        stageSystem(option)
    else:
        stageFunction(stage)
        stageSystem() # recursive call
stageSystem()

It might look lengthy, but it works pretty well considering you have 4 stages.

  • Related