Coding - Python 3

Python – Make a (huge or not) menu NOT in a while loop

The first big project I did during my studies was about the MVC architecture in which a main menu was needed. Having little knowledge in programming at that time, I created that menu IN a while loop, which is a mistake, because whatever called in that menu will be run in that loop, which can lead to crashes, if not the collapse of the Universe. I remember some weird stuff happened once or thrice, but I can’t recall what precisely. With practice, I came up (yes, by myself) with a menu that would NOT run in a while loop, but instead use external inputs that would use while loops and constrain the inputs’ results to whatever the maker wants.

In this short tutorial, I’ll show you how to create a menu, navigate to its elements and either “return” to the menu or quit the program.


SETTING UP

Create your working folder and inside it 3 empty python files:
__init__.py
main.py where our main program will be
menu_views.py where we’ll put the inputs functions
Let’s start with menu_views.py.


menu_views.py – CREATING THE INPUTS

That’s a very important part that covers one of the basics: the while loop. A while loop is a loop that’ll keep running as long as the conditions to get out of it aren’t met. Which can be “dangerous” as it can easily lead to an infinite loop.
For that program, I want 2 inputs:
– one to choose from the menu (think of it as a list from which you pick ONE item)
– one to choose to either go back to the menu or exit. That input is called in the item chosen from the menu (it’ll be clearer once you see the code)

Create your first function: def choose_language():
Directly, we start our loop with while True: and our whole input will belong to that loop. When the input is valid, it is returned and the program leaves the loop, else if runs again from the start.
I want to give the user 5 options: “1. English”, “2. French”, “3. German”, “4. Swedish”, “exit. Exit the program”. Here, you want to be careful as to where to place your input. If you place it BEFORE the options, the latter won’t show up, as the input “pauses” the program, waiting for the user to actually enter and validate something. So what I do is something like:
“Please choose a language:”
LIST HERE (“1. English” etc.)
INPUT: “Your choice:”
CHECK THE INPUT and process accordingly

The tricky part, if I may write, with inputs is that if they aren’t properly checked, whatever entered by the user can be processed. For example, if you ask the user to enter “y” or “n”, the “y” will usually be checked and lead to something, whereas the “n” isn’t as the developer used a “else” or “elif” without enough constraints. I’ve seen it many times.
A super easy way to avoid that is to set the possible inputs in a list. So here it is, a way to do:
choices = [“1”, “2”, “3”, “4”, “exit”]
With that, the user does not have a choice but to enter “1”, “2”, “3”, “4” or “exit”. If not, then whatever the input was, the loop will just start over.

So here is our little function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def choose_language():
    while True:
        choices = ["1", "2", "3", "4", "exit"]
        print("Please choose a language:")
        print("1. English")
        print("2. French")
        print("3. German")
        print("4. Swedish")
        print("exit. Exit the program")
        choice = input("\nYour choice: ")

        if choice in choices:
            return choice
        else:
            print("\n\tWrong input, please try again.\n")
            continue

Cool! Now the function def back_to_menu():
Here, I simply want to ask if the user wants to go back to the menu or not. “y”=yes and “n”=exit the program. That function ONLY returns “y” or “n”, or loops again if the input is unexpected. That returned result will then be used in a different function to control the behavior of the program.

1
2
3
4
5
6
7
8
def back_to_menu():
    while True:
        choice = input("Would you like to return to the main menu (y/n)? ").casefold()
        if choice == "y" or choice == "n":
            return choice
        else:
            print("\n\tWrong input, please try again.\n")
            continue

.casefold() is a “trick” that converts whatever the user entered to lowercase. Therefore, even if the user mistakenly entered “Y” (instead of “y”), it would be changed into “y” and the program would be able to keep going instead of returning a “Wrong input” message, which could somehow upset the user.


main.py – IMPORT THE INPUTS AND BUILD THE MENU

First thing to do: import the views by typing import menu_views (you import your file as a python module). Once it’s done, we can call the functions we wrote in that file. It may sound like an obvious feature, but that’s something I find really cool, regardless of the language.

Create the function for your menu: def main_menu():
And directly call the target function by assigning it to a variable: choice = menu_views.choose_language()
Because the function we call is an input, it will directly be “started” and display to the user the above menu “Please choose a language:  etc.”. And remember, it is a WHILE LOOP, so as long as the user hasn’t entered a valid input, the program won’t keep going on!
Which leads to what’s got to come right after: check what valid input the user entered. And that input is limited to only FIVE things: “1”, “2”, “3”, “4” or “exit”. Meaning you do NOT need to think about other possibilities and can focus on your actual menu. With that, we can simply use 5 if, checking the value of choice.
If choice = 1, then load the English language, and so on. If choice = exit, close the program.
That’s all! And you don’t need to use elif nor else, because again: the choice is limited to a given list.

I don’t know if there is an easier way to do, but I find that one extremely practical, logical, straightforward and easily maintainable. What? Who said I was boasting?!

1
2
3
4
5
6
7
8
9
10
11
12
13
def main_menu():
    choice = menu_views.choose_language()
    if choice == "1":
        English()
    if choice == "2":
        French()
    if choice == "3":
        German()
    if choice == "4":
        Swedish()
    if choice == "exit":
        print("Byebyyyyyye")
        exit()

What are those “English()”, “French()” and all, you ask? Wait a little more, let’s create our def back_to_menu(): function. As its name suggests, it will be used to go back to… no, not the future you fucking nerd, the menu, yes!
And it’s in that function that we’re going to call the one we wrote in the views. So again, create a variable and call it:
choice = menu_views.back_to_menu()
That one returned only TWO things: “y” or “n”, so we can use if and else, because each will be either one of the limited inputs. Maaan it’s really easy like that, isn’t it?
So we’ll do if choice = y, load the menu, else farewell amazing program.

1
2
3
4
5
6
def back_to_menu():
    choice = menu_views.back_to_menu()
    if choice == "y":
        main_menu()
    else:
        exit()

Now we just need to make those “English()”, “French()” etc. functions, in which we put our actions: just a print for that tutorial, followed by the function we just created above: back_to_menu().

Call the main function main_menu() at the end of your file (or else nothing will happen when you run your program), and voilààà!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import menu_views


def main_menu():
    choice = menu_views.choose_language()
    if choice == "1":
        English()
    if choice == "2":
        French()
    if choice == "3":
        German()
    if choice == "4":
        Swedish()
    if choice == "exit":
        print("Byebyyyyyye")
        exit()


def back_to_menu():
    choice = menu_views.back_to_menu()
    if choice == "y":
        main_menu()
    else:
        exit()


def English():
    print("You chose English")
    back_to_menu()


def French():
    print("You chose French")
    back_to_menu()


def German():
    print("You chose German")
    back_to_menu()


def Swedish():
    print("You chose Swedish")
    back_to_menu()


main_menu()

Run it, test it, you should be having something quite cool.

You can use that method to create complex menus without having to worry about running a sub-menu in a loop from which you’ll never get out of.


If I have made a mistake somewhere or forgotten anything, let me know!

Leave a Reply