-1

I am currently writing a basic program with multiple menus. I have a function called menu1(), which is called in main and handles the first set of menu options. My issue I am having is being able to return to main() from my menu1() function. In menu1() I have a while loop which continues to display the menu after the user has inputted their selection so that they don't have to restart the program every time. If I include a return statement in menu1() it just returns to the start of menu1() and displays those menu prompts again. Here is my menu1() function, which is called the main:

def menu1(Stock:list[StockItem]): """ Handles the Stock menu user selections """ choice:str = "" print("") print("Stock menu") print("") print("1. Add new stock") print("2. Remove stock from system") print("3. Add quantity to existing stock") print("4. Remove quantity from existing stock") print("5. Display all stock") print("6. Return to previous menu") print("") choice = input("Please select option: ") while choice not in ["1", "2", "3", "4", "5", "6"]: print("Invalid selection") choice = input("Please select option: ") while choice != "6": match choice: case "1": add_stock(Stock) return case "2": remove_stock(Stock) return case "3": item = input("Enter stock item name to add quantity: ").upper() amount = input_int("Enter quantity to add: ") update_existing_stock(Stock, item, amount) return case "4": item = input("Enter stock item name to remove quantity: ").upper() amount = input_int("Enter quantity to remove: ") update_existing_stock(Stock, item, -amount) return case "5": display_all_stock(Stock) return case "6": return 

I have tried return and break statements however neither have worked. Does anyone have any suggestions?

2
  • 1
    Presumably the code which calls menu1() calls it again after it returned. But we can't see that code and suggest how to change it. Commented Sep 14, 2024 at 15:04
  • The way to return to caller function is the return statement. you have it and as you tell it's not working. I can think about two resons: the caller function is not main or you call menu1 function again. I'm sure there are things I can't think of now, so we need to check the whole program. Commented Sep 14, 2024 at 16:25

1 Answer 1

0

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

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for that! Thankfully since posting I figured out the problem and fixed it.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.