Python Menu-Driven Programming

Menu driven program to print other programs

You need to sort your indents.

def mainMenu():
print("1. lst")
print("2. a")
print("3. quit")
while True:
selection=int(input("Enter Choice: "))
if selection==1:
lst()
elif selection==2:
a()
elif selection==3:
exit()
else:
print("Invalid choice. Enter 1-3")
mainMenu() # Also watch for recursion here

and your second part

def lst():
lst = []
num = int(input("How many numbers: "))
for n in range(num):
numbers = int(input("Enter the numbers"))
lst.append(numbers)
print("Maximum element in the list is :", max(lst), "\nMinimum element in the list is :", min(lst))

Running the below code

def lst():
lst = []
num = int(input("How many numbers: "))
for n in range(num):
numbers = int(input("Enter the numbers"))
lst.append(numbers)
print("Maximum element in the list is :", max(lst), "\nMinimum element in the list is :", min(lst))

def mainMenu():
print("1. lst")
print("2. a")
print("3. quit")
while True:
selection=int(input("Enter Choice: "))
if selection==1:
lst()
elif selection==2:
a()
elif selection==3:
exit()
else:
print("Invalid choice. Enter 1-3")
mainMenu() # Also watch for recursion here

mainMenu()

creates this output

1. lst
2. a
3. quit
Enter Choice: 1
How many numbers: 5
Enter the numbers1
Enter the numbers2
Enter the numbers3
Enter the numbers4
Enter the numbers5
Maximum element in the list is : 5
Minimum element in the list is : 1
Enter Choice: ^C

Menu driven python program to pass value in command line

i am assuming that you are passing only one argument, you need to replace argv[i] with argv[1][i] wherever applicable

from sys import argv
print(argv[1])
print("enter 1 for counting, 2 for sum and 3 for sorting the letter")
choice=int(input("enter choice: "))
if choice==1:
alphabets = digits = special = 0
for i in range(len(argv[1])):
if((argv[1][i] >= 'a' and argv[1][i] <= 'z') or (argv[1][i] >= 'A' and argvargv[1][i] <= 'Z')):
alphabets = alphabets + 1
elif(argv[1][i] >= '0' and argv[1][i] <= '9'):
digits = digits + 1
else:
special = special + 1
print("Total Number of Alphabets : ", alphabets)
print("Total Number of Digits : ", digits)
print("Total Number of Special Characters : ", special)
elif choice==2:
sum=0
for i in range(len(argv[1])):
if(argv[1][i].isdigit()):
sum=sum+int(argv[1][i])
print(sum)
if sum%2==0:
print("sum is even")
else:
print("sum is odd")
elif choice==3:
s=""
for i in range(len(argv[1])):
if((argv[1][i] >= 'a' and argv[1][i] <= 'z') or
(argv[1][i] >= 'A' and argv[1][i] <= 'Z')):
s=s+argv[1][i]
# print(s)
def sortdes(str):
str.sort(reverse = True)
str1 = ''.join(str)
print(str1)
s1=list(s)
sortdes(s1)

Menu-driven collection of non-negative integers

Corrected code with minimum changes:

def main():
myList = []
choice = 1
while choice != 6:
if choice == 1:
option1(myList)
elif choice == 2:
option2(myList)
elif choice == 3:
option3(myList)
elif choice == 4:
option4(myList)
elif choice == 5:
option5(myList)
choice = displayMenu()


print ("\nThanks for playing!\n\n")

def displayMenu():
myChoice = 0
while myChoice not in [1, 2, 3, 4, 5]:
print("""\n\nPlease choose
1. Add a number to the list/array
2. Display the mean
3. Display the median
4. Print the list/array
5. Print the list/array in reverse order
6. Quit
""")
myChoice = int(input("Enter option---> "))
if myChoice not in [1, 2, 3, 4, 5]:
print("Invalid option. Please select again.")

return myChoice

# Option 1: Add a number to the list/array
def option1(myList):
num = -1
while num < 0:
num = int(input("\n\nEnter a non-negative integer: "))
if num < 0:
print("Invalid value. Please re-enter.")
myList.append(num)


# Option 2: Display the mean
def option2(myList):
print("The mean is ", sum(myList) / len(myList))

# Option 3: Display the median
def option3(myList):
sortedlist = sorted(myList)
if len(sortedlist) % 2:
median = myList[int(len(sortedlist) / 2)]
else:
center = int(len(sortedlist) / 2)
median = sum(myList[center-1:center+1]) / 2
print("The median is", median)


# Option 4: Print the list/array
def option4(myList):
print(sorted(myList))

# Option 5: Print the list/array in reverse order
def option5(myList):
print(sorted(myList, reverse=True))


main()
How I would do this:

The first part of the following code are a set of constants to customize the style of the menu. Then a set of functions representing each option are defined. The following 3 functions should not be modified, they generate the menu, display it and close the application. Then the main section starts, where you need to pass every option as an argument to setOptions(). The rest should not be modified either as it is the main loop.

# Menu formatting constants
MENU_HEADER = "Please choose an option:"
MENU_FORMAT = " * {:2}. {}"
MENU_QUIT_S = "Quit"
MENU_ASK_IN = "Enter option: "
MENU_INT_ER = "ERROR: Invalid integer. Please select again."
MENU_OPT_ER = "ERROR: Invalid option. Please select again."
END_MESSAGE = "Thanks for playing!"

# OPTIONS FUNCTIONS START HERE

def addElement(l):
""" Add a number to the list/array. """
n = -1
while n < 0:
try:
n = int(input("Enter a non-negative integer: "))
except ValueError:
print("It needs to be an integer.")
n = -1
else:
if n < 0:
print("It needs to be a non-negative integer.")
l.append(n)


def mean(l):
""" Calculate the mean. """
print("Mean: {:7.2}".format(sum(l) / len(l)))


def median(l):
""" Calculate the median. """
l = sorted(l)
p = int(len(l) / 2)
print("Median: {:7.2}".format(l[p] if len(l)%2 else sum(l[p-1:p+1])/2))


def oprint(l):
""" Print the list/array. """
print(sorted(l))


def rprint(l):
""" Print the list/array in reverse order. """
print(sorted(l, reverse=True))

# OPTIONS FUNCTIONS END HERE

def onQuit(l):
""" Function to execute when quitting the application. """
global quit
quit = True
print(END_MESSAGE)


def setOptions(*args):
""" Generates the menu and the options list. """
# Menu header and quit option (option 0)
menu = [MENU_HEADER]
options = [onQuit]
# Passed arguments represent texts and functions of additional options
for i, f in enumerate(args, start=1):
menu.append(MENU_FORMAT.format(i, f.__doc__.strip()))
options.append(f)
# We print the option 0 the last one
menu.append(MENU_FORMAT.format(0, MENU_QUIT_S))
# Returning both the menu and the options lists
return tuple(menu), tuple(options)


def displayMenu(menu):
""" Display the menu and get an option that is an int. """
while True:
for line in menu:
print(line)
try:
choice = int(input(MENU_ASK_IN))
except ValueError:
print(MENU_INT_ER)
else:
return choice

if __name__ == '__main__':
# Pass the option functions to the setOptions function as arguments
menu, options = setOptions(
addElement,
mean,
median,
oprint,
rprint
)
# Initiate the needed variables and start the loop
l = []
quit = False
while not quit:
c = displayMenu(menu)
try:
f = options[c]
except IndexError:
print(MENU_OPT_ER)
else:
f(l)

What is the error in this menu driven program to input records of students in a binary file (name,roll,age,marks) and perform the following operations

Your issue is that you are reading the contents but not storing them again. But this code is yelling for some auxiliar functions so that everything stays clean. Lets start making some helper functions and solving the issue in the meanwhile.

We are requesting several integers from the user so lets create a function that handles this. It will return a special number (defaults to 0) in case we can't convert what the user provided to an integer.

def input_integer(request: str, *, error: int = 0) -> int:
try:
return int(input(request))
except ValueError: # If we can't convert to integer return error
return error

Note: if you are not used to the type annotations, they mean that the input_integer function expects a string argument (which is the message to request the integer) and a keyword integer argument that allows to configure which integer to return as an error, defaulting to 0. The function returns an integer. By making this annotations the reader will have better understanding of what the function does and IDEs will detect some type mismatch errors, but they will not be evaluated at runtime.

Okey so we are going to print a menu, lets also make a function for it. Actually, we are going to make a function that returns a function. The outter funtion will build the menu itself, and the returned function will print it and request for the user input.

def menu_factory(options: List[str], input_request: str) -> Callable[[], int]:
# Number of options
options_number = len(options)

# Menu text
menu_text_lines = ["MENU:"]
for i, option in enumerate(options):
menu_text_lines.append(f"\t{i+1}. {option}")
menu_text = "\n".join(menu_text_lines)

# Input request text
input_request += f" (1..{options_number}): "

# Create the function that will be called to print the menu
def menu_function() -> int:
# Print the menu text we have previously built
print(menu_text)

# Get the input from the user until he gives a valid one
choice = input_integer(input_request)
while not(0 < choice <= options_number):
print(f"It must be a number between 1 and {options_number}.")
choice = input_integer(input_request)

# Return the choice of the user
return choice

return menu_function

As you can see, functions can be defined inside other blocks and returned as any other object would have been. The function accepts a list of strings which are the options and an additional string to request the user for input. It will build the full messages adding the numbers and prepare the function that we will later call. In this case, the menu_factory function would be called like this:

menu = menu_factory(
[
"Create Binary File.",
"Display Binary File.",
"Search for a given roll number.",
"Input roll number and mark, Update mark of the student.",
"Delete a record for a given roll number.",
"Display the details of the students getting average marks "
"more than 80.",
"Append new records at the end of file.",
"Exit",
],
"Choose a command"
)

And now, menu() will print the menu, request the user choice and return that choice after validating it is a proper number in the correct range.

The next thing we will have is a class to store the information of each student instead of a list. It will have 4 attributes (name, roll number, age and mark). The constructor (__init__) will just save them. I also added a __repr__ that tells python how to print Student objects. The __slots__ at the top of the class definition is a memory optimization. By setting __slots__ we tell the class which exact attributes it will have instead of having to store them as a generic dictionary. If you remove this line it will still work exactly the same, but each student you load will consume a little bit more RAM.

class Student:
__slots__ = 'name', 'roll_no', 'age', 'mark'

def __init__(self, name: str, roll_no: int, age: int, mark: int) -> None:
self.name = name
self.roll_no = roll_no
self.age = age
self.mark = mark

def __repr__(self) -> str:
return f"Student<name={self.name}, roll_no={self.roll_no}, " \
f"age={self.age}, mark={self.mark}>"

We are pretty much done but there is another thing that we will do quite a bunch of times, reading and writting to the file. Lets create some auxiliar functions for that to. The read_file function will create a list of Stundets. The first try: ... except FileNotFoundError: pass block detects if the file can't be found (retunring an empty list of Students). The with open(...) as f: ... if a better approach than calling f.close() afterwards. Python itself will close the file when you get out of that with block, doesn't matter if it is due to an exception or any other reason. So basically we know for sure that the file will be closed no matter what. The inner try: ... except EOFError: break is to detect when have we ended reading the file and get out of the infinite while True: ... loop.

def read_file(path: str) -> List[Student]:
content = []
try:
with open(path, 'rb') as f:
while True:
try:
content.append(pickle.load(f))
except EOFError: # Break the loop when reached end of the file
break
except FileNotFoundError: # Don't raise if the file doesn't exist
pass
return content

The write function is pretty simple, open the file, write the content, done. Same goes for append.

def write_file(path: str, content: List[Student]) -> None:
with open(path, 'wb') as f:
for row in content:
pickle.dump(row, f)


def append_file(path: str, content: List[Student]) -> None:
with open(path, 'ab') as f:
for row in content:
pickle.dump(row, f)

So now we have an input_integer function to read integers from the user, a menu_factory function that will build the menu, a Student class that will store each student's info, and a read_file, write_file and append_file functions. We can start implementing our logic. I'm going to create a dictionary of functions where the key is going to be the integer choice and the value are the functions that we will call to implemnent that option. You will see how choice_X functions will be super simple now that we have set up those auxiliary methods.

import pickle
from typing import Callable, List


FILENAME = 'student.bat'


def input_integer(request: str, *, error: int = 0) -> int:
# ...


def menu_factory(options: List[str], input_request: str) -> Callable[[], int]:
# ...


class Student:
# ...


def read_file(path: str) -> List[Student]:
# ...


def write_file(path: str, content: List[Student]) -> None:
# ...


def append_file(path: str, content: List[Student]) -> None:
# ...


if __name__ == '__main__' :
# Create the menu function from the factory
menu = menu_factory(
[
"Create Binary File.",
"Display Binary File.",
"Search for a given roll number.",
"Input roll number and mark, Update mark of the student.",
"Delete a record for a given roll number.",
"Display the details of the students getting average marks "
"more than 80.",
"Append new records at the end of file.",
"Exit",
],
"Choose a command"
)

def choice_1() -> None:
students = []
for i in range(1, input_integer("How many entries? ") + 1):
print(f"Entry number {i}:")
students.append(Student(
input("\tName: "),
input_integer("\tRoll number: "),
input_integer("\tStudent age: "),
input_integer("\tAverage mark: "),
))
write_file(FILENAME, students)

def choice_2() -> None:
print(read_file(FILENAME))

def choice_3() -> None:
roll_no = input_integer("Roll number of the student to find: ")
for student in read_file(FILENAME):
if student.roll_no == roll_no:
print(student)
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")

def choice_4() -> None:
roll_no = input_integer("Roll number of the student to update: ")
students = read_file(FILENAME)
for i, student in enumerate(students):
if student.roll_no == roll_no:
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
return

students[i].mark = input_integer("New average mark: ")
write_file(FILENAME, students)

def choice_5() -> None:
roll_no = input_integer("Roll number of the student to delete: ")
students = read_file(FILENAME)
for i, student in enumerate(students):
if student.roll_no == roll_no:
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
return

del students[i]
write_file(FILENAME, students)

def choice_6() -> None:
for i, student in enumerate(read_file(FILENAME)):
if student.mark >= 80:
print(student)

def choice_7() -> None:
students = []
for i in range(1, input_integer("How many entries? ") + 1):
print(f"Entry number {i}:")
students.append(Student(
input("\tName: "),
input_integer("\tRoll number: "),
input_integer("\tStudent age: "),
input_integer("\tAverage mark: "),
))
append_file(FILENAME, students)

menu_callbacks = {
1: choice_1,
2: choice_2,
3: choice_3,
4: choice_4,
5: choice_5,
6: choice_6,
7: choice_7,
}

# Option number 8 is Exit
while (choice := menu()) != 8:
print()
try:
callback = menu_callbacks[choice]
except KeyError:
print("NOT IMPLEMENTED YET")
else:
callback()
print("\n")


Related Topics



Leave a reply



Submit