10
\$\begingroup\$

Trying to learn a new skill at 40 without any prior related experience :-) Bought the book 'Python crash course 2e' and decided to freewheel a bit with after a week with what I've learned so far.. I put everything in a small program to order pizzas and I would love some feedback before I take up bad habits..

first off: although I think I understand the concept of functions and classes, I didn't see the need to use these because it was quite simple.. but now it's getting a bit difficult. I tried to get away with simple lists and dictionaries to store orders and prices.. But trouble emerges when you want to order 2 of the same pizzas with different toppings (you get identical keys). Also, giving the price for a final order was nice, but if you want to delete a pizza from the order, I can't think of a way to delete the items from the list.

Maybe someone can give me some feedback in what direction I should look for a solution?

#making the lists
available_pizzas = ['margarita', 'pollo', '4cheese', 'bolognese', 'vegetarian']
available_toppings = ['mushroom', 'onions', 'green pepper', 'extra cheese']
pizza_prices = {'margarita': 5, 'pollo': 7, '4cheese': 6, 'bolognese': 8, 'vegetarian': 6.5}
topping_prices = {'mushroom':1, 'onions': 2, 'green pepper':3, 'extra cheese':4}
sub_total = []
final_order = {}
customer_adress = {}


#ordering a pizza
print("Hi, welcome to our text based pizza ordering")
order_pizza = True
while order_pizza:    
    print("Please choose a pizza: ")
    print()
    for pizzas in available_pizzas:
        print(pizzas)
        print()
    while True:
        pizza = input("which pizza would you like to order?")
        if pizza in available_pizzas:
            print(f"You have ordered a {pizza}.")
            sub_total.append(pizza_prices[pizza])
            break
        if pizza not in available_pizzas:
            print(f"I am sorry, we currently do not have {pizza}.")

    #asking for extra toppings
    order_topping = True
    print("This is the list of available extra toppings: ")
    for toppings in available_toppings:
        print(toppings)
        print()
    while order_topping:
        extra_topping = input("Would you like an extra topping? yes or no?")
        if extra_topping == "yes":
            topping = input("Which one would you like to add?")
            if topping in available_toppings:
                final_order.setdefault(pizza, [])
                final_order[pizza].append(topping)
                print(f"I have added {topping}.")
                sub_total.append(topping_prices[topping])
            else:
                print(f"I am sorry, we don't have {topping} available.")

        elif extra_topping == "no":
            break
    extra_pizza = input("Would you like to order another pizza?")
    if extra_pizza == "no":
        for key, value in final_order.items():
            print(f"\nYou have order a {key} pizza with {value}")
        check_order = True
        while check_order:
            print()
            order_correct = input("Is this correct? yes/no ")
            if order_correct == "yes":
                check_order = False
                order_pizza = False
            if order_correct == "no":
                print(final_order)
                add_remove = input("would you like to add or remove? ")
                if add_remove == "remove":
                    remove = input("Which pizza would you like to remove? ")
                    del final_order[remove]
                    print(final_order)
                if add_remove == "add":
                    check_order = False

#finalizing the order
print(f"\nYour total order price is: ${sum(sub_total)}")

print("Please provide us with your name, adress and phonenumber")
customer_adress['name'] = input("what is your name?")
customer_adress['street_name'] = input("What is your streetname and housenumber?")
customer_adress['postalcode'] = input("What is the postalcode and cityname?")
customer_adress['phonenumber'] = input("What is your phonenumber?")
print()
print(f"Thank you for your order {customer_adress['name']}.")
print()
print("We will deliver your order to this adres ASAP")
print()
print(customer_adress['street_name'])
print(customer_adress['postalcode'])
print()
print(f"we will contact you on {customer_adress['phonenumber']} if anything comes up.")   
    
\$\endgroup\$
  • \$\begingroup\$ What version of Python are you using? Are you using Python 3.7+? \$\endgroup\$ – Peilonrayz Sep 27 at 0:30
  • \$\begingroup\$ @Peilonrayz Thanks. Python 3.8.3. \$\endgroup\$ – Osman Polat Sep 27 at 5:38
  • \$\begingroup\$ @OsmanPolat consider accepting one of the answers \$\endgroup\$ – Aryan Parekh Oct 8 at 5:19
8
\$\begingroup\$

Welcome to CR community.

  1. Keep constant declarations at the top. Although you follow the PEP8 naming conventions throughout (almost) the whole code base, constant (or globals) are named as UPPER_SNAKE_CASE. So, the pizza_prices would become PIZZA_PRICES.

  2. Use triple-quoted strings in python for multiline content. Your print statements would look a lot cleaner (no need for empty print() statements).

  3. Put the execution flow of your code inside the if __name__ == "__main__" block.

  4. Instead of having separate variables for list of pizza/toppings and their prices, keep only the mapping of pizza/toppings, and you can get list of pizza/toppings using the dict.items() iterator.

  5. Since a majority of code execution is dependent on valid input choice from the user; it's better to provide those choices in the input call. For eg:

    extra_pizza = input("Would you like to order another pizza?")
    

    does not make it clear where the user should type "y/Y/Yes/N/n/No/Cancel/Quit". Putting this choice selection in a separate function would be more helpful:

    def get_user_choice(message, *choices):
        prompt = f"{message}\n\nChoicese are: {' '.join(choices)}"
        while True:
            choice = input(prompt)
            if choice in choices:
                return choice
            print("Wrong selection")
    

    now call the above as follows:

    add_remove = get_user_choice("would you like to add or remove?", "add", "remove")
    
  6. As you're beginning with programming, I'd suggest gathering associated resources into a class, instead of using a dictionary. For eg. a Customer class, with name, phone etc. attributes. Another Pizza class with associated type and toppings etc.


To expand on point 4:

PIZZA_PRICING = {
    "margarita": 5,
    "pollo": 7,
    "4cheese": 6,
    "bolognese": 8,
    "vegetarian": 6.5,
}

Asking user's preference for pizza:

pizza_choice = get_user_choice("Please choose a pizza:", *PIZZA_PRICING.keys())
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ thank you for your feedback! I'm still figuring out on when and where to use classes. But I didn't get the dictionary part. How do I store for example the ordered pizza with toppings in a class? It needs to 'remember' somehow I guess, any link with info on this? \$\endgroup\$ – Osman Polat Sep 27 at 14:17
  • \$\begingroup\$ @OsmanPolat updated my post above/ \$\endgroup\$ – hjpotter92 Sep 27 at 15:18
2
\$\begingroup\$

Your code is quite easy to follow. So good job for that. There is still some room for improvement. Not loads of changes.


Clear screen

Python has certain functions to clear any text printed on the console. Check this page for all the information.

if you are on windows, you can pip install os and then import os at the top of your program to use these functions.

For example, os.system('pause') can be used to wait for the user to click any key after you show them a message.

Use '\n'

I'm not sure why I see many empty print()'s but I think you are trying to print a newline. By default after using the print() function there will always be a newline at the end of the text. But if you want to print more, use '\n'. For example, After you have printed something

Wrong:

print("Hello,World!")
print()
print("Yay")

Output:

Hello World!


Yay

Correct:

print("Hello,World!\n")
print("Yay")

Output:

Hello World!


Yay

Use Functions

Move the order-taking part into a function this way. You can also make a new function called ShowMenu() to print to the menu each time you call the function.

def ShowMenu():
    os.system('cls')
    print("Available Pizzas:\n")
    print(*available_pizzas,sep = ', ')
    print("\n\nAvailable Topings:\n")
    print(*available_toppings,sep = ', ')
    print('\n\n')

def TakeOrderInput():
    os.system('cls')
    print("Hi, welcome to our text based pizza ordering")
    ordering = True
    while ordering:
        os.system('cls')
        ShowMenu()
        pizza = input("Please choose a pizza: ")
        if pizza not in available_pizzas:
            print(f"I am sorry, we currently do not have {pizza}\n.")
            os.system('pause')
            continue
        topping = input("Please choose a topping: ")
        if topping not in available_toppings:
            print(f"I am sorry, we currently do not have {topping}\n.")
            os.system('pause')
            continue

        print(f"Final order: {pizza} with topping {topping}: ")
        ordering = False

    return pizza,topping

What do you do now when you want to take a new order?

pizza, topping = TakeOrderInput()

Object-oriented programming

If you don't know what OOP is, it's time that you learn about it as It helps you make your code much cleaner and moreover HELPS you code better.

There's no rule that you have to use Object-oriented programming, it is completely up to you as you are the developer and it's your style. But here is a typical implementation of classes in context to your program.

class Order:
    def __init__(self):
        taxes = 0 #You can add taxes
        pizza,topping = TakeOrderInput()
        self.type = pizza
        self.topping = topping
        self.PizzaPrice = pizza_prices[pizza]
        self.ToppingPrice = topping_prices[topping]
        self.Total = self.PizzaPrice + self.ToppingPrice
        print(self.Total)

Of course this a just a small implementation of classes, once you learn more you can add more stuff like billing address, taxes et cetera.

Take a new order

With all that we have done. On its own it does nothing. We need to now use these functions

choice = True
orders = []
orderchoice = input("Welcome! Would you like to order ? (y/n): ")
if orderchoice == 'n':
    print("Have a nice day!")
else:
    while choice:
        neworder = Order()
        orders.append(neworder)
        newchoice = input("Would you like to order again? (y/n): ")
        if (newchoice) == 'n':
            break

This will finally make a list of all the orders the user has given. To access anything iterate through the list and then get the attribute. For example, If you want to get the total cost.

total = 0
for order in orders:
    total+=order.Total

print(total)

Final

Here is what your program would look like with all the changes

import os

available_pizzas = ['margarita', 'pollo', '4cheese', 'bolognese', 'vegetarian']
available_toppings = ['mushroom', 'onions', 'green pepper', 'extra cheese']
pizza_prices = {'margarita': 5, 'pollo': 7, '4cheese': 6, 'bolognese': 8, 'vegetarian': 6.5}
topping_prices = {'mushroom':1, 'onions': 2, 'green pepper':3, 'extra cheese':4}

def ShowMenu():
    os.system('cls')
    print("Available Pizzas:\n")
    print(*available_pizzas,sep = ', ')
    print("\n\nAvailable Topings:\n")
    print(*available_toppings,sep = ', ')
    print('\n\n')

def TakeOrderInput():
    os.system('cls')
    print("Hi, welcome to our text based pizza ordering")
    ordering = True
    while ordering:
        os.system('cls')
        ShowMenu()
        pizza = input("Please choose a pizza: ")
        if pizza not in available_pizzas:
            print(f"I am sorry, we currently do not have {pizza}\n.")
            os.system('pause')
            continue
        topping = input("Please choose a topping: ")
        if topping not in available_toppings:
            print(f"I am sorry, we currently do not have {topping}\n.")
            os.system('pause')
            continue

        print(f"Final order: {pizza} with topping {topping}: ")
        ordering = False

    return pizza,topping

class Order:
    def __init__(self):
        taxes = 0 #You can add taxes
        pizza,topping = TakeOrderInput()
        self.type = pizza
        self.topping = topping
        self.PizzaPrice = pizza_prices[pizza]
        self.ToppingPrice = topping_prices[topping]
        self.Total = self.PizzaPrice + self.ToppingPrice





choice = True
orders = []
orderchoice = input("Welcome! Would you like to order ? (y/n): ")
if orderchoice == 'n':
    print("Have a nice day!")
else:
    while choice:
        neworder = Order()
        orders.append(neworder)
        newchoice = input("Would you like to order again? (y/n): ")
        if (newchoice) == 'n':
            break

total = 0
for order in orders:
    total+=order.Total

print("Total: ",total, '$')

I haven't done anything to the final part which was the address, Phone number et cetera, you can add those things as you wish.

I hope you found this review useful 😁

| improve this answer | |
\$\endgroup\$
  • 3
    \$\begingroup\$ function names in python follow lower_snake_case naming convention. \$\endgroup\$ – hjpotter92 Sep 27 at 11:26
  • \$\begingroup\$ @hjpotter92 As long as the naming convention is clear to you and others reading your code, consistent, not too big, not too small. I believe it is one's choice. \$\endgroup\$ – Aryan Parekh Sep 27 at 11:27
  • 3
    \$\begingroup\$ Please do not teach people to call os.system() for trivial tasks like clearing the screen or waiting for a keypress. This is a very costly operation (it needs to create a new process, start a shell interpreter, and interpret the command), and it is not portable. To wait for input, you can just print('Press Enter to continue'); input(), to clear the screen you can print an ANSI escape code: print('\x1b[2J'). That is way more efficient and while not perfectly portable, still better than os.system('cls'). \$\endgroup\$ – G. Sliepen Sep 27 at 12:57
  • \$\begingroup\$ @G.Sliepen what shall I use to clear the screen? \$\endgroup\$ – Aryan Parekh Sep 27 at 13:16
  • 1
    \$\begingroup\$ See this answer for how to clear the screen by just print()ing a so-called ANSI escape code. \$\endgroup\$ – G. Sliepen Sep 27 at 13:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.