Since you have a while loop that shows the menu again, When you call return, A single iteration of that loop ends and next one starts which is why the menu is displayed again (as you said). To go back to main() function, instead of return use main().
For Example:
In menu1, option 6 goes back to main menu, therefore the code should be:
... case "5": display_all_stock(Stock) return case "6": main()
However, since the while loop condition is while choice!="6", it will never execute the 6th option.
Since the main() function has a while loop, the above solution might be problematic as it might generate a very long program tree. You can define a variable at the top of your script or if you are implementing in a class, then a class Attribute to store a boolean value of when to break the loop.
Class Implementation
import sys class Menu: def __init__(self): self.choice: str = "" # choice self.menu0_choices = {1: "Show Stock Options", 2: "Quit"} # Main Menu self.menu1_choices = {1: "Add New Stock", 2: "Go Back to Previous Menu"} # Menu 1 def show_menu0(self) -> bool: """This function will return True when You have to repeat this menu, False when you have to go back or quit""" print("Menu 0") for idx, opt in self.menu0_choices.items(): print(idx, opt) self.choice = input("Please select an option: ") while int(self.choice) not in self.menu0_choices.keys(): print("Invalid Selection! Try again") self.choice = input("Your choice: ") while self.choice != str(list(self.menu0_choices.keys())[-1]): match self.choice: case "1": # Here the next menu will be shown return True # if choice == "2", the loop will exit return False def show_menu1(self) -> bool: # Similar code as show_menu0 def main(): menu = Menu() while True: # show the main menu first if not menu.show_menu0(): sys.exit(0) # exit if main menu exits else: # if main menu is supposed to show a sub menu if not menu.show_menu1(): continue else: # show another sub menu
If you have multiple sub-menus emerging from a single menu, then instead of using bool return type of the class method, use str. Give a name to each of the sub-menus, and return the name of sub-menus from the class method and handle them in the main method. Similarly, Instead of returning False return a string "break" or anything of your choice which will be handled in the main method.
import sys class MenuErr(Exception): pass class Menu: def __init__(self): self.menus = [ {"menu": "0", 1: "show stock options", 2: "Exit"}, # menu 0 {"menu": "0.1", 1: "Add Stock", 2: "Remove", 3: "Go Back"}, # sub-menu-1 of menu 1 {"menu": "0.1.1", 1: "Do something", 2: "Go back"}, # sub-menu-1 of sub-menu-1 of menu 1 ] self.current_menu = "0" def goback(self) -> str: """returns the prev menu, else raises an exception""" if self.current_menu == "0": sys.exit(0) else: # parts = [1, 1, 1] for "1.1.1" parts = self.current_menu.split('.') parts = parts[:len(parts)-1] # remove the last element prev = '.'.join(parts) # get the resulting string -> 1.1 for menu in self.menus: # check if '1.1' exists if menu['menu'] == prev: # return if exists return menu["menu"] # if doesn't exist, raise exception raise MenuErr("Previous Menu Not Found.") def gonext(self) -> str: """returns the next menu in the order 1 -> 2, 1.1 -> 2, 1.1.1 -> 2""" # next means if it is menu "0", go to menu "1" next_ = int(self.current_menu.split('.')[1]) + 1 for menu in self.menus: if menu['menu'] == next_: return menu["menu"] raise MenuErr("No next menu found.") def go_sub_next(self, same: bool) -> str: """if menu is at 1, it will show 1.1 if menu is at 1.1, if same is True, return 1.2 else return 1.1.1 """ if '.' not in self.current_menu: new = self.current_menu + '.1' elif same: parts = self.current_menu.split('.') parts[-1] = str(int(parts[-1]) + 1) new = '.'.join(parts) else: new = self.current_menu + '.1' for menu in self.menus: if menu["menu"] == new: return new raise MenuErr("No Next Sub Menu") def show_menu(self, menu: str = "0") -> str: for m in self.menus: if m['menu'] == menu: # print the menu for idx, opt in m.items(): if idx != "menu": print(idx, opt) # capture input choice = input("Your Choice: ") return choice break raise MenuErr(f"No menu: {menu}") # Implementation def main(): back_trigger: bool = False while True: menu = Menu() choice = menu.show_menu(menu="0") # first menu match choice: case "1": # Go to next menu # again match the choice here for sub menu while not back_trigger: next_menu = menu.go_sub_next(same=True) # this will return 0.1 as current is 0 nextchoice = menu.show_menu(next_menu) match nextchoice: case "1": # do something pass case "2": # this is the go back option back_trigger = True continue # this will go back to the loop control and exit as back_trigger is False if back_trigger: # once outside the loop, check back_trigger back_trigger = False continue ...
Use a mixture of all these to create a proper menu style!
Please share the complete relevant code for a better answer
menu1()calls it again after it returned. But we can't see that code and suggest how to change it.