Python Forum

Full Version: Pizza Ordering Program
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I finally finished this program today! Tell me what you think of it and how I could make it better. Thanks!

""" Scripted by Trinx """
#Freddie's Pizza Ordering System  
pricem = {'Sausage': 0.65, 'Peperoni': 0.39, 'Chicken': 0.35, 'Pineapple': 0.23, 'Mushroom': 0.68}

def ptopping1():
    print('\nPricing:\n\tChicken \t$0.35')
    print('\tSausage \t$0.65')
    print('\tPeperoni \t$0.39')
    print('\tPineapple \t$0.23')
    print('\tMushroom  \t$0.68')
    print('\tTotal:\t\t${:4.2f}'.format(total) + '\n')

def ptopping2():
    print('\nPricing:\n\tSmall 8" \t$4.00')
    print('\tMedium 12" \t$5.75')
    print('\tLarge 16" \t$7.50')
    print('\tCustom calculated by diameter of pizza.\tEach inch is $0.52\n')

for word in 'Welcome to Freddie\'s Pizza'.split():
    print(f'{word.capitalize():=^65}')
print("\n")
import time
time.sleep(0.5)
print('At anytime when ordering, type "Pricing" to show the pricing\n')
time.sleep(1.3)
print('of ingredients and the total cost of your pizza so far.\n')
time.sleep(1.3)
ordering = True
order = list()
order = []
total = 0


while ordering:
    size = input('What size pizza would you like, small, medium, large or custom?')
    if size.upper()[0] == 'S':
        print('\n\tSmall pizza selected.')
        order.append('"Small" pizza')
        total = total + 4
        print('\nYou must pick three toppings.')
        num2 = 1
        while num2 != 4:
            print('\nPlease select your topping.')
            topping1 = input('\nChicken, Sausage, Peperoni, Pineapple, Mushroom:').title()
            if topping1[0] == 'C':
                total = total + pricem['Chicken']
                order.append('Chicken')
                num2 = num2 + 1
                print('\n\tChicken topping selected.')
            elif topping1[0] == 'S':
                total = total + pricem['Sausage']
                order.append('Sausage')
                num2 = num2 + 1
                print('\n\tSausage topping selected.')
            elif topping1.upper()[1] == 'E':
                total = total + pricem['Peperoni']
                order.append('Peperoni')
                num2 = num2 + 1
                print('\n\tPeperoni topping selected.')
            elif topping1.upper()[1] == 'I':
                total = total + pricem['Pineapple']
                order.append('Pineapple')
                num2 = num2 + 1
                print('\n\tPineapple topping selected.')
            elif topping1[0] == 'M':
                total = total + pricem['Mushroom']
                order.append('Mushroom')
                num2 = num2 + 1
                print('\n\tMushroom topping selected.')
            elif topping1.upper()[1] == 'R':
                ptopping1()
            else:
                print('Error!')
        print('\nDone ordering')
        print('You selected a ' + order[0] + ' with\nthe following toppings: ' + order[1] + ', ' + order[2] + ' and ' + order[3] + '.')
        tot2 = total * 1.060
        tot1 = total * 0.06
        print('Your total is: ${:4.2f}'.format(total) + ' with ${:4.2f}'.format(tot1) + ' tax, equal to ${:4.2f}'.format(tot2))
        print('Thank you for your order.')
      

       
    elif size.upper()[0] == 'M':
        order.append('Medium Pizza')
        print('\n\tMedium pizza selected.')
        total = total + 5.75
        print('\nYou may pick three toppings.')
        num1 = 1
        while num1 != 4:
            print('\nPlease select a topping.')
            topping1 = input('\nChicken, Sausage, Peperoni, Pineapple, Mushroom:').title()
            if topping1[0] == 'C':
                total = total + pricem['Chicken']
                order.append('Chicken')
                num1 = num1 + 1
                print('\n\tChicken topping selected.')                            
            elif topping1[0] == 'S':
                total = total + pricem['Sausage']
                order.append('Sausage')
                num1 = num1 + 1
                print('\n\tSausage topping selected.')                
            elif topping1.upper()[1] == 'E':
                total = total + pricem['Peperoni']
                order.append('Peperoni')
                num1 = num1 + 1
                print('\n\tPeperoni topping selected.')                
            elif topping1.upper()[1] == 'I':
                total = total + pricem['Pineapple']
                order.append('Pineapple')
                num1 = num1 + 1
                print('\n\tPineapple topping selected.')                
            elif topping1[0] == 'M':
                total = total + pricem['Mushroom']
                order.append('Mushroom')
                num1 = num1 + 1
                print('\n\tMushroom topping selected.')                
            elif topping1.upper()[1] == 'R':
                ptopping1()
            else:
                print('Error!')
        print('\nDone ordering')
        print('You selected a ' + order[0] + ' with\nthe following toppings: ' + order[1] + ', ' + order[2] + ' and ' + order[3] + '.')
        tot2 = total * 1.060
        tot1 = total * 0.06
        print('Your total is: ${:4.2f}'.format(total) + ' with ${:4.2f}'.format(tot1) + ' tax, equal to ${:4.2f}'.format(tot2))
        print('Thank you for your order.')
    


    elif size.upper()[0] == 'L':
        order.append('Large Pizza')
        print('\n\tLarge pizza selected.')
        total = total + 7.50
        print('\nYou may pick three toppings.')
        num = 1
        while num != 4:
            print('\nPlease select a topping.')
            topping1 = input('\nChicken, Sausage, Peperoni, Pineapple, Mushroom:').title()
            if topping1[0] == 'C':
                total = total + pricem['Chicken']
                order.append('Chicken')
                num = num + 1
                print('\n\tChicken topping selected.')                            
            elif topping1[0] == 'S':
                total = total + pricem['Sausage']
                order.append('Sausage')
                num = num + 1
                print('\n\tSausage topping selected.')                
            elif topping1.upper()[1] == 'E':
                total = total + pricem['Peperoni']
                order.append('Peperoni')
                num = num + 1
                print('\n\tPeperoni topping selected.')                
            elif topping1.upper()[1] == 'I':
                total = total + pricem['Pineapple']
                order.append('Pineapple')
                num = num + 1
                print('\n\tPineapple topping selected.')                
            elif topping1[0] == 'M':
                total = total + pricem['Mushroom']
                order.append('Mushroom')
                num = num + 1
                print('\n\tMushroom topping selected.') 
            elif topping1.upper()[1] == 'R':
                ptopping1()
            else:
                print('Error!')
        print('\nDone ordering')
        print('You selected a ' + order[0] + ' with\nthe following toppings: ' + order[1] + ', ' + order[2] + ' and ' + order[3] + '.')
        tot2 = total * 1.060
        tot1 = total * 0.06
        print('Your total is: ${:4.2f}'.format(total) + ' with ${:4.2f}'.format(tot1) + ' tax, equal to ${:4.2f}'.format(tot2))
        print('Thank you for your order.')

        
    
    elif size.upper()[0] == 'C':
        print('\n\tCustom size selected.')
        num1 = 1
        while num1 != 2:
            psize = int(input('\nWhat size in inches would you like the diameter of your pizza to be?'))
            if psize > 50:
                print('\nPlease select less than or a 50" pizza.')
            elif psize < 3:
                print('\nPlease select more than or a 3" pizza') 
            elif psize <= 50 and psize >= 3:
                num1 = num1 + 1
        order.append('' + str(psize)[0:4] + '" Custom pizza')
        print('\n' + str(psize) + '" pizza selected.')
        psize = psize * 0.52
        total = total + psize
        print('\nYou may pick three toppings.')
        num = 1
        while num != 4:
            print('\nPlease select a topping.')
            topping1 = input('\nChicken, Sausage, Peperoni, Pineapple, Mushroom:').title()
            if topping1[0] == 'C':
                total = total + pricem['Chicken']
                order.append('Chicken')
                num = num + 1
                print('\n\tChicken topping selected.')                            
            elif topping1[0] == 'S':
                total = total + pricem['Sausage']
                order.append('Sausage')
                num = num + 1
                print('\n\tSausage topping selected.')                
            elif topping1.upper()[1] == 'E':
                total = total + pricem['Peperoni']
                order.append('Peperoni')
                num = num + 1
                print('\n\tPeperoni topping selected.')                
            elif topping1.upper()[1] == 'I':
                total = total + pricem['Pineapple']
                order.append('Pineapple')
                num = num + 1
                print('\n\tPineapple topping selected.')                
            elif topping1[0] == 'M':
                total = total + pricem['Mushroom']
                order.append('Mushroom')
                num = num + 1
                print('\n\tMushroom topping selected.') 
            elif topping1.upper()[1] == 'R':
                ptopping1()
            else:
                print('Error!')
        print('\nDone ordering')
        print('You selected a ' + order[0] + ' with\nthe following toppings: ' + order[1] + ', ' + order[2] + ' and ' + order[3] + '.')
        tot2 = total * 1.060
        tot1 = total * 0.06
        print('Your total is: ${:4.2f}'.format(total) + ' with ${:4.2f}'.format(tot1) + ' tax, equal to ${:4.2f}'.format(tot2))
        print('Thank you for your order.\n')


    
    elif size.upper()[0] == 'P':
        ptopping2()
        
    else:
        print('Sorry, unexpected error. Please try again.')

    cont = input('Would you like to order another pizza?')
    if cont.upper()[0] == 'Y':
        total = 0
        del order[0:4]
    elif cont.upper()[0] == 'N':
        print('\nThank you!')
        break
    else:
        print('\nYo no entender, lo sentimos, salir de. A intentarlo mas tarde.')
        break

#PS my name is not Freddie.
Some observations:

- Import should be at the beginning, before any code (import time)

- you can improve your code by separating what you do and how you do it. It can be achieved by using more functions with descriptive names; maybe use top-down style with main()
Some other observations:

- your prices (pricem) and printout of prices (functions ptopping1, ptopping2) are not related. This means that any changes in pricing (pricem) is not reflected in printout. This gonna be significant problem if you update prices or add/remove items etc. You should take data for 'pretty-print' from your pricelist. Then all price updates and changes are reflected in pricing printouts as well.

- I advise to print explicitly. Define functions that return something and print result of the function. Functions that print something but does not have return statement actually return None. It may cause problems. Furthermore, it is good to have as much as possible of control of your code flow. You call a function (without parameters and with nondescriptive name) and by reading the code you have no idea what will happen.

I had little spare time when waiting for my child and I refactored beginning of your program with top-down style. There is very little of code and long docstrings. My experience is - if you have any code what is longer than couple of rows then you should document it for yourself. If you are returning to it in couple of weeks and you look at your code it usually seems that somebody else has written it and you have no clue how and why this code is written in a such way.

There is code with my thought process:

def main():
    pass


main()
Then I wrote welcome message part:

def main():
    print(centered_with_padding("Welcome to Freddie's Pizza"))

def centered_with_padding(text):
    pass
I put some thought into that welcome message. I want it to be understandable that it will be printed out (thus print). I want it to be more or less self-explanatory what format is applied (thus name centered_with_padding), I want to show what is the printed message (thus it takes message as argument). Then I maybe overthinking but decide to be defensive. Maybe at some point widht (65) or padding character (=) are deemed 'wrong' by 'art-director' :-). Therefore I use keyword arguments with default settings with ability to change them if need arises.

Considering all this I came up with oneliner function with long docstring:

def main():
    print(centered_with_padding("Welcome to Freddie's Pizza"))     # should be self-explanatory what will happen
     


def centered_with_padding(text, *, width=65, padding='='):
    """
    Return formatted text as string.

    Formatting: split text into words; every word on separate row and centered with padding.
    Width of row and padding character are provided with keyword arguments.

    :param text: text to be formatted
    :type text: str
    :param width: width of the row in return string
    :type width: int
    :param padding: char to be used as row padding in return string
    :type padding: str
    :return: text with formatting applied
    :rtype: str

    """
    return '\n'.join([f'{word.capitalize():{padding}^{width}}' for word in text.split()])

main()
I can run my file and see that so far my program behaves as expected. I can play with arguments to find optimal width and padding character.

Now I think about message about pricing availability. As this message is too long I decided to put this into function and gave hint about the content with descriptive name. So the code looks like this now:

def main():
    print(centered_with_padding("Welcome to Freddie's Pizza"))
    print(pricing_availability_notification()) 


def centered_with_padding(text, *, width=65, padding='='):
    """
    Return formatted text as string.

    Formatting: split text into words; every word on separate row and centered with padding.
    Width of row and padding character are provided with keyword arguments.

    :param text: text to be formatted
    :type text: str
    :param width: width of the row in return string
    :type width: int
    :param padding: char to be used as row padding in return string
    :type padding: str
    :return: text with formatting applied
    :rtype: str

    """
    return '\n'.join([f'{word.capitalize():{padding}^{width}}' for word in text.split()])

    
def pricing_availability_notification():
    """
    Return string with  pricing availability notification.

    Formatting: every statement in statements list on new row.

    :return: notifications listed in statements
    :rtype: str
    """

    statements = [
                  'At anytime when ordering, type "Pricing" (without quotes) to ',
                  'show pricing of ingredients and the total cost of your pizza so far.']
                 ]
    
    return '\n'.join(statements)

main()


At this point my time run out :-)
(Jan-18-2019, 08:10 AM)perfringo Wrote: [ -> ]Some other observations: - your prices (pricem) and printout of prices (functions ptopping1, ptopping2) are not related. This means that any changes in pricing (pricem) is not reflected in printout. This gonna be significant problem if you update prices or add/remove items etc. You should take data for 'pretty-print' from your pricelist. Then all price updates and changes are reflected in pricing printouts as well. - I advise to print explicitly. Define functions that return something and print result of the function. Functions that print something but does not have return statement actually return None. It may cause problems. Furthermore, it is good to have as much as possible of control of your code flow. You call a function (without parameters and with nondescriptive name) and by reading the code you have no idea what will happen. I had little spare time when waiting for my child and I refactored beginning of your program with top-down style. There is very little of code and long docstrings. My experience is - if you have any code what is longer than couple of rows then you should document it for yourself. If you are returning to it in couple of weeks and you look at your code it usually seems that somebody else has written it and you have no clue how and why this code is written in a such way. There is code with my thought process:
 def main(): pass main() 
Then I wrote welcome message part:
 def main(): print(centered_with_padding("Welcome to Freddie's Pizza")) def centered_with_padding(text): pass 
I put some thought into that welcome message. I want it to be understandable that it will be printed out (thus print). I want it to be more or less self-explanatory what format is applied (thus name centered_with_padding), I want to show what is the printed message (thus it takes message as argument). Then I maybe overthinking but decide to be defensive. Maybe at some point widht (65) or padding character (=) are deemed 'wrong' by 'art-director' :-). Therefore I use keyword arguments with default settings with ability to change them if need arises. Considering all this I came up with oneliner function with long docstring:
 def main(): print(centered_with_padding("Welcome to Freddie's Pizza")) # should be self-explanatory what will happen def centered_with_padding(text, *, width=65, padding='='): """ Return formatted text as string. Formatting: split text into words; every word on separate row and centered with padding. Width of row and padding character are provided with keyword arguments. :param text: text to be formatted :type text: str :param width: width of the row in return string :type width: int :param padding: char to be used as row padding in return string :type padding: str :return: text with formatting applied :rtype: str """ return '\n'.join([f'{word.capitalize():{padding}^{width}}' for word in text.split()]) main() 
I can run my file and see that so far my program behaves as expected. I can play with arguments to find optimal width and padding character. Now I think about message about pricing availability. As this message is too long I decided to put this into function and gave hint about the content with descriptive name. So the code looks like this now:
 def main(): print(centered_with_padding("Welcome to Freddie's Pizza")) print(pricing_availability_notification()) def centered_with_padding(text, *, width=65, padding='='): """ Return formatted text as string. Formatting: split text into words; every word on separate row and centered with padding. Width of row and padding character are provided with keyword arguments. :param text: text to be formatted :type text: str :param width: width of the row in return string :type width: int :param padding: char to be used as row padding in return string :type padding: str :return: text with formatting applied :rtype: str """ return '\n'.join([f'{word.capitalize():{padding}^{width}}' for word in text.split()]) def pricing_availability_notification(): """ Return string with pricing availability notification. Formatting: every statement in statements list on new row. :return: notifications listed in statements :rtype: str """ statements = [ 'At anytime when ordering, type "Pricing" (without quotes) to ', 'show pricing of ingredients and the total cost of your pizza so far.'] ] return '\n'.join(statements) main() 
At this point my time run out :-)

Wow, thanks for the suggestions. Why did you do this:

def main():
    print(centered_with_padding("Welcome to Freddie's Pizza"))     # should be self-explanatory what will happen
 
Mainly I was wondering why you defined it.
(Jan-22-2019, 03:25 PM)Trinx Wrote: [ -> ]Wow, thanks for the suggestions. Why did you do this:

def main():
    print(centered_with_padding("Welcome to Freddie's Pizza"))     # should be self-explanatory what will happen
 
Mainly I was wondering why you defined it.

It is good practice to use main() for WHAT you do and keeping HOW you do in functions. This way main() is more or less description what is done and if there is need to check/debug how it's done then you go to underlying function.

Regarding defining function: this is for stating that something is printed out; there is formatting applied (centered, padding) and there is message to which this formatting applied. No need to read (sometimes complicated) code to understand what is going on. How it is done is explained in function (both docstring and code).

This style helps beginner programmers avoid pitfalls of spaghetti code
That makes sense now, thanks. I'll edit my code with your suggestions and post it when I'm done. Smile