This week's book giveaway is in the Go forum.
We're giving away four copies of Head First Go and have Jay McGavren on-line!
See this thread for details.
Win a copy of Head First Go this week in the Go forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
Sheriffs:
  • Devaka Cooray
  • Junilu Lacar
  • Tim Cooke
Saloon Keepers:
  • Tim Moores
  • Ron McLeod
  • Tim Holloway
  • Claude Moore
  • Stephan van Hulst
Bartenders:
  • Winston Gutkowski
  • Carey Brown
  • Frits Walraven

Battling with python assignment design  RSS feed

 
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi guys

i have this task to do for a drinks menu system:

shown a list of 5 drinks (3 alcoholic, 2 nonalcoholic) and their individual prices.

The user should be asked to choose a drink as well as the quantity.

If the drink is alcoholic, then the user should be asked if all drinkers are over 18. If not, the
user is informed that only non-alcoholic drinks may be ordered and allowed to choose again.

Every third alcoholic drink is free. (Use an average of the total alcoholic drink cost to calculate deduction.)
VAT at 22.5% will be added to the total alcoholic drinks bill (after discount has been applied).

After ordering a drinks option the user should have the option to choose a different drink or return to
the main menu.

On choosing to return to the main menu a fully itemised account of that drinks order is displayed;

drink type (non/alcoholic), number per type, number of free drinks, undiscounted total, total discount,
VAT, etc.

(1. You may assume that the user will only enter valid values for the quantity of drinks
2. You may assume that once an order has been accepted for a particular drink that it will not be
   ordered again).

so far i have the menu



but im not sure where to start? do i code in each if? or do i create functions for isAlchoholic and quantity?  
im just really lost when it comes to implementing a design from paper to code

any advice or help would be priceless at this stage


 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
am i on the right track here?

why wont this line work? trying to add the quantity to the over all count
global alcoholicDrinksTotal = alcoholicDrinksTotal + 1

alcoholicDrinksTotal = 0
softDrinksTotal = 0

def getDrinks(name,alc,price,quantity):
   if alc:
       customerChoice = False
       while not customerChoice:
           customerAge = (input("Are the drinkers over 18 years old (y)es or (n)o:")).upper()
           if customerAge == "N":
               print("You are too young to drink alcohol, please select a different drink.\n")
               drinksMenu()
           elif customerAge == "Y":
               global alcoholicDrinksTotal = alcoholicDrinksTotal + 1

           else:
               customerAge = (input("Are the drinkers over 18 years old (y)es or (n)o:")).upper()
   else:
       print("invalid input")



def drinksMenu():
   alcoholicDrinksTotal = 0
   softDrinksTotal = 0

   print("Please select which drink to purchase:")
   print("1: Beer\t\t\t€5.40")
   print("2: Wine\t\t\t€4.10")
   print("3: Vodka\t\t€7.20")
   print("4: Coke\t\t\t€3.20")
   print("5: Sprite\t\t€3.00")
   print("6: Return to main menu.")

   selection = int(input("\nPlease enter your selection [1 - 6]:"))
   if selection == 1:
       quantity = int(input("How many beer/s would you like?:"))
       getDrinks("beer", True, 5.40, quantity)


   # elif selection == 2:
   #     wineQuantity = int(input("How many glasses of wine would you like?:"))
   #     isAlcoholic = True
   #
   # elif selection == 3:
   #     vodkaQuantity = int(input("How many vodkas would you like?:"))
   #     isAlcoholic = True
   #
   # elif selection == 4:
   #     cokeQuantity = int(input("How many cokes would you like?:"))
   #     isAlcoholic = False
   #
   # elif selection == 5:
   #     vodkaQuantity = int(input("How many sprites would you like?:"))
   #     isAlcoholic = False
   # elif selection == 6:
   #     print("Call main menu function here")
   # else:
   #     print("Invalid selection, enter 1 to 6\n")
   #     drinksMenu()

drinksMenu()
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
sorry forgot code tags

 
Greenhorn
Posts: 26
Python VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Wayne,

Looks like you have taken a serious stab at the problem.  Here are a few "nudges" to help you along:

*    Python uses a certain construct to start programs which looks like
   
  The program may want to have a loop in this starting area to have it repeatedly call the drink menu function.

*    Passing the drink request information as parameters to the drink serving function is an excellent idea.  This avoids  the need for globals (which is usually avoided by experienced Python developers due to the complexity it adds to debugging).

*    Once the drink serving function has code added to handle non-alcoholic drinks, it can be used for any of the drink requests.

The program as is is at the moment is a great start.  Good luck with adding the rest of the functionality and with your journey to learn Python.  
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for your input

my code will be part of a bigger program so it will be called from another menu, good to know what you showed me as i can apply that to the main code
other than that i have a few more bits to write in

any other criticism? what do you think of the menu system that doesnt use a loop just ifs and else? are there any pitfalls regarding this?

thanks again
 
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A couple of pitfalls:

1. It's a little too clever because it hides the fact that there is still in essence, a loop. It's better to be explicit about those kind of things.

2. You are basically making a recursive call. Since Python does not do tail-call recursion optimization, you run the risk of blowing the call stack after X number of recursive calls (maybe around a thousand calls). While it may be unlikely you'll ever get to that limit, the risk is still there. If it does happen, you'll get a nice stack overflow exception.

How did you get the idea to do a recursive call instead of a loop? Usually, people think it's clever but I think it's better to write clear code.
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"You are basically making a recursive call. Since Python does not do tail-call recursion optimization, you run the risk of blowing the call stack after X number of recursive calls (maybe around a thousand calls). While it may be unlikely you'll ever get to that limit, the risk is still there. If it does happen, you'll get a nice stack overflow exception."

can you please explain more about this,this is regarding the loop handling the main drinks menu right?
 
Junilu Lacar
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My advice is to break the problem down into smaller tasks. If you find yourself writing more than 20 lines of code to do something, you're probably trying to do too much in one section of code.

Most of the code I write is broken down into small manageable chunks that require only about five lines of code. I may get some that are 10-15 lines of code but more often than not, I can keep it to less than 10 lines. This makes everything in even the most complex problem simpler.
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the tip

is there too much in one area happening in my code? or is that a general tip?

also when using global variables do you have to use
global variable before actually using it?
i tried global drinksTotal += 1 but it wouldnt work
i then went global drinksTotal
drinksTotal += 1

is this normal?
 
Junilu Lacar
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Your drinks menu is a good example of being too "greedy" and doing more than one thing in a chunk of code. Why are you setting your totals in a method that is supposed to just handle displaying a menu? Initializing totals has nothing to do with displaying a menu so why have that logic in there? And because you tried to eliminate an explicit loop, you just introduced a bug. Every time your drinks menu gets called recursively, you are re-initializing your totals to zero, clobbering whatever value you already had saved there. That bug is your clever little trick coming back to bite you.
 
Junilu Lacar
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I can't emphasize this point enough. The word "battling" in the subject of this post is exactly the right word. What you're battling, however, is not the problem or the language. You're battling complexity and you're inflicting pain on yourself by writing way too much code in one place. Always think "How can I make this simpler?"

Programming is an inherently complex task so you should do everything you can to make the job simpler. Not breaking up the problem into smaller problems just makes things worse for you.

Choose good names, write clear and expressive code, eliminate redundancy, encapsulate (hide implementation details and keep behaviors close to the data they rely upon), and most importantly, test your code as you go, not all at once at the end. It's easier to test as you go when you break the problem down into smaller problems.
 
Junilu Lacar
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Quick explanation of a recursive call: When a method calls itself.

The way you had it set up, the recursive call makes it look like your program is in a loop. The difference, however, is that you are repeatedly nesting calls to the drinks menu function. Python will do only a limited number of recursive/nested calls like that, I believe only up to something like a thousand.
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
great thanks for all that!!! very encouraging
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"Your drinks menu is a good example of being too "greedy" and doing more than one thing in a chunk of code. Why are you setting your totals in a method that is supposed to just handle displaying a menu?"

how am i supposed to get the function to understand whats being ordered? and how much?
why do i even need 1 to 6 for each drink then?
i could just have it running the getDrink function if 1 to 6 is pressed, but i cant see how else to make the drink selection to that drink unique.
 
Junilu Lacar
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

wayne brandon wrote:how am i supposed to get the function to understand whats being ordered? and how much?


The question isn't how but why a function like drinksMenu() needs to understand what's being ordered. Shouldn't it only be concerned with displaying the menu options?

The idea is to keep responsibilities separate so you can manage logic easily. If you mix different responsibilities together in one function, that function becomes 100% more complicated.


Which of the functions above do you think should contain the logic to zero out total when a new order is created?

Another question: Have you learned about tuples and lists? Because I think these are the kind of structures you'll need for this problem.
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
def start_new_order: im guessing

no, we havent covered lists and tuples even though im quite familiar with them we were not allowed to use them, really thanks so much for your help, appreciated
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
so really, your functions only contain about 20 lines of code?
 
wayne brandon
Ranch Foreman
Posts: 135
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar so in my drink menu would i just pass say 1 2 3 4 5 into my function
then in the function have more if statements?
if 1 then enter quantity add a price = etc etc

also why do i have to call a global variable before i can use it?

myTotal = 100

def addNumbers():
   anotherNumber = 5
   myTotal + anotherNumber * 2 (This doesnt work)
   global myTotal + anotherNumber * 2 (Neither does this)
   global myTotal
   myTotal + anotherNumber * 2 (This works)

why is that?


 
Junilu Lacar
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

wayne brandon wrote:so really, your functions only contain about 20 lines of code?


Even fewer. I strive for 1-5 lines of code to keep things really simple. 10-20 lines of code would be some kind of detailed algorithm or multi-line display-related logic.

The longer a method ir function is, the more complicated it becomes. That makes it harder to work with, understand, and test. That makes it more likely to harbor bugs. So many more bad things can happen when the code in a method/function is long so I tend to make mine very short. I'm lazy that way.
 
Junilu Lacar
Sheriff
Posts: 13187
219
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It looks like myTotal needs to be accessed by multiple functions so you need to declare it with a wider scope. It's like a global public variable.
 
Consider Paul's rocket mass heater.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!