Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
coding improvement tips
#1
Hi All,
I am apologizing in advance if it wastes your time. Because it's not a question regarding any topic. It is for my improvement. Experts can suggest to me what would be the better option that could be used. I believe Feedbacks are the best way to improve oneself.
So here is my project. Its a simple project of a restaurant.
Flow:
Code as user whether he would like to order something?
If it's Yes --> The code displays the menu
---> Ask for the food items he would like to place?
---> Once the user is done with the order. A final bill is displayed.

Restaurant.py
""" This module is a restaurant program.
    Ask user input to place an order. Provide multiple options to user
    to choose. """

class TajRestaurant:
    """
    Class TajRestaurant ask user input to place an order
    """
    # class variable
    tables_occupied = 0
    max_tables = 10

    menu = {'burger': {'hamburger': 5, 'chicken': 7},
            'pizza': {'cheese': 6, 'veg': 8}}
    def __init__(self):
        if TajRestaurant.max_tables < 10:

            TajRestaurant.tables_occupied += 1
            self.bill_amount = 0
            self.print_menu()
            self.take_order()
        else:
            print(" Sorry we are full. Kindly wait")
        
    def get_status(self):
        msg = input(" Would you like to place an order anything?? \n").lower()
        if msg == "yes":
            return True
        elif msg == "no":
            return False
        else:
            print("Invalid Input. ")
            exit()

    def print_menu(self):
        for food, sub_food in TajRestaurant.menu.items():
            for items, price in sub_food.items():
                print(items + " " + food + '\n  =====================', "Price: $", price)

    def take_order(self):
        status = self.get_status()
        total_order = []
        while status:
            user_order = input(" What would you like to have? ").lower()
            food_status = self.check_item_availability(user_order)

            if food_status:  # collect all the food items to bill
                total_order.append(user_order)

            status = self.get_status()
            if status == False:
                self.cashier(total_order)
                break
        if status == False:
            print("Thanks you for your visit ")

    def check_item_availability(self, food_item):
        fstatus = False
        for _, sub_food in TajRestaurant.menu.items():
            if food_item in sub_food:
                fstatus = True
                break
            else:
                fstatus = False
        if fstatus:
            print("Item Available ")
        else:
            print("Unavailable !")
        return fstatus


    def get_price(self, ordered_food):
        
        for _, sub_food in TajRestaurant.menu.items():
            for user_food in ordered_food:
                if user_food in sub_food:
                    self.bill_amount += int(sub_food[user_food])
        return self.bill_amount

    def cashier(self, user_food):
        bill = self.get_price(user_food)
        print("Your bill is: $" + str(bill))
    print(" Welcome to Taj Restaurant !!!")
Reply
#2
Not a waste of time at all. This forum's here for people looking to learn and improve.

The first things that jumped out at me were the class name and __init__(). They are too specific. The __init__() is meant to create an instance of a class rather than running the internal code of that class. To make it more general, I would make these changes:

class Restaurant:

    def __init__(self, name, tables, **menu):
        self.name = name
        self.max_tables = tables
        self.menu = menu
        tables_occupied = 0

taj_menu = {
    'burger': {'hamburger': 5, 'chicken': 7},
    'pizza': {'cheese': 6, 'veg': 8}
}
taj = Restaurant("TajRestaurant", 10, **taj_menu)
Now, this could be TajRestaurant or Ricardo's Ristorante or Jim's Pizza Emporium with different numbers of tables, different menus, etc.

Of course, it no longer has a means to admit a new customer to the restaurant. Let's fix that and add a means to remove a customer:

def admit_new_customer(self):
    if self.tables_occupied < self.max_tables:
        self.tables_occupied += 1
    else:
        print(" Sorry we are full. Kindly wait")

def remove_customer(self):
    self.tables_occupied -= 1
    print("Thank you! Come again!")
Let's look at how our customers are ordering their food. To me, get_status() doesn't add much; if we're calling take_order(), we can suppose that the customer will answer "yes" to get_status(). Without this though, we'll need to give the customer an option to stop ordering.

Then, it calls check_item_availability() which is good. The result does not need to be stored though, we can just call the method in the if statement and be done with it.

def take_order(self):
    total_order = []
    while True:
        self.print_menu()
        user_order = input("What would you like to have?").lower()

        if user_order in ("no", "nothing", "done", "exit", "finished", "full"):
            break
        
        if self.check_item_availability(user_order):  # collect all the food items to bill
            total_order.append(user_order)
        else: print("Sorry, we don't sell that...")

    return total_order
For check_item_availability(), we can simplify the method:

def check_item_availability(self, food_item):
    return food_item in self.menu.keys()
Of course, that supposes that we aren't allowing options on the menu items. The customer could order a burger but could not select between beef and chicken. Either the menu formatting would have to change to accommodate. Personally, I would change the menu to:

taj_menu = {
    'hamburger': 5,
    'chicken sandwich': 7,
    'cheese pizza': 6, 
    'veg pizza': 8
}
We can simplify get_price() as well. Instead of iterating over the menu (which could be lengthy), it should iterate over the order since that should be shorter. We can get the prices with a dict.get() call.

def get_price(self, ordered_food):
    total = 0
    for item in ordered_food:
        total += self.menu.get(item)

    return total
The cashier() method can be simplified a little:

def cashier(self, user_food):
    print("Your bill is: $" + str(self.get_price(user_food)))
Finally, we need to run the code so, let's add a run() method. My implementation is very basic, but you get the idea:

def run(self):
    while True:
        self.admit_new_customer()
        order = self.take_order()
        self.cashier(order)
        # or self.cashier(self.take_order())
        self.remove_customer()   
The final result of this refactoring is this:

""" This module is a restaurant program.
    Ask user input to place an order. Provide multiple options to user
    to choose. """
 
class Restaurant:

    def __init__(self, name, tables, **menu):
        self.name = name
        self.max_tables = tables
        self.menu = menu
        tables_occupied = 0

    def admit_new_customer(self):
        if self.tables_occupied < self.max_tables:
            self.tables_occupied += 1
        else:
            print(" Sorry we are full. Kindly wait")

    def remove_customer(self):
        self.tables_occupied -= 1
        print("Thank you! Come again!")

    def take_order(self):
        total_order = []
        while True:
            self.print_menu()
            user_order = input("What would you like to have?").lower()

            if user_order in ("no", "nothing", "done", "exit", "finished", "full"):
                break
            
            if self.check_item_availability(user_order):  # collect all the food items to bill
                total_order.append(user_order)
            else: print("Sorry, we don't sell that...")

        return total_order
 
    def print_menu(self):
        for food in TajRestaurant.menu:
            print(food, " ", '\n  =====================', "Price: $" + self.menu.get(food))
  
    def check_item_availability(self, food_item):
        return food_item in self.menu.keys()

    def get_price(self, ordered_food):
        total = 0
        for item in ordered_food:
            total += self.menu.get(item)

        return total
 
    def cashier(self, user_food):
        print("Your bill is: $" + str(self.get_price(user_food)))

    def run(self):
        while True:
            self.admit_new_customer()
            order = self.take_order()
            self.cashier(order)
            # or self.cashier(self.take_order())
            self.remove_customer()            
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Any tips to how to find out values? nevlindan 1 689 Apr-27-2023, 09:14 PM
Last Post: deanhystad
  Random coordinate generator speed improvement saidc 0 2,021 Aug-01-2021, 11:09 PM
Last Post: saidc
  Function Improvement Santino 1 1,768 May-23-2020, 03:30 PM
Last Post: jefsummers
  Name Mashup Program Improvement in Python rhat398 3 2,516 Apr-05-2020, 12:09 PM
Last Post: perfringo
  first try with python class, suggestion for improvement please anna 18 5,727 Nov-01-2019, 11:16 AM
Last Post: anna
  Tips for CLI program with Keybinding system pedropessoa 2 2,546 Nov-21-2018, 09:59 AM
Last Post: Gribouillis
  indentation tips Pedroski55 4 3,198 Sep-16-2018, 10:21 AM
Last Post: Gribouillis
  Web Scraping efficiency improvement HiImNew 0 2,364 Jun-01-2018, 08:52 PM
Last Post: HiImNew
  Router interface status through SNMP - suggestion required for improvement. anna 0 2,993 Feb-27-2018, 11:10 AM
Last Post: anna
  Organizing tips Demini 1 2,185 Feb-10-2018, 05:32 AM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020