My solution to Basta fazoolin

This was how I handled Basta Fazoolin. Not terribly elegant, but I think I grasped the basic concepts reasonably well. Open to any opinions other’s may have…

class Menu:
  def __init__(self,name,items,start_time,end_time):
    self.name = name
    self.items = items
    self.start_time = start_time
    self.end_time = end_time
  
  def __repr__(self):
    return "{name} menu available from {start_time} to {end_time}".format(name = self.name,start_time = self.start_time,end_time = self.end_time)

  def calculate_bill(self,purchased_items):
    self.purchased_items = purchased_items
    bill = []
    for item in purchased_items:
      for key,value in self.items.items():
        if item == key:
          bill.append(value)
    return sum(bill)
           
brunch = Menu("Brunch",{'pancakes': 7.50, 'waffles': 9.00, 'burger': 11.00, 'home fries': 4.50, 'coffee': 1.50, 'espresso': 3.00, 'tea': 1.00, 'mimosa': 10.50, 'orange juice': 3.50
},11,16)

early_bird = Menu("Early_Bird",{'salumeria plate': 8.00, 'salad and breadsticks (serves 2, no refills)': 14.00, 'pizza with quattro formaggi': 9.00, 'duck ragu': 17.50, 'mushroom ravioli (vegan)': 13.50, 'coffee': 1.50, 'espresso': 3.00,
},15,18)

dinner = Menu("Dinner",{'crostini with eggplant caponata': 13.00, 'ceaser salad': 16.00, 'pizza with quattro formaggi': 11.00, 'duck ragu': 19.50, 'mushroom ravioli (vegan)': 13.50, 'coffee': 2.00, 'espresso': 3.00,
},17,23)

kids = Menu("kids",{'chicken nuggets': 6.50, 'fusilli with wild mushrooms': 12.00, 'apple juice': 3.00
},11,21)

arepas_menu = Menu("Take a/' Arepa",
  {'arepa pabellon': 7.00, 'pernil arepa': 8.50, 'guayanes arepa': 8.00, 'jamon arepa': 7.50
},10,20)


class Franchise:
  def __init__(self,address,menus):
    self.address = address
    self.menus = menus
  def __repr__(self):
    return "Our store is located at {location}.".format(location = self.address)

  def available_menus(self,time):
    self.time = time
    menulist = []
    for menu in self.menus:
        if time >= menu.start_time and time <= menu.end_time:
          for keys in menu.items:
            menulist.append(keys)
    print (menulist)

flagship_store = Franchise("1232 West End Road",[brunch,early_bird,dinner,kids])
new_installment = Franchise("12 East Mulberry Street",[brunch,early_bird,dinner,kids])
arepas_place = Franchise("189 Fitzgerald Avenue",[arepas_menu])


class Business:
  def __init__(self,name,franchises):
    self.name = name
    self.franchises  = franchises
    

biz1 = Business("Basta Fazoolin' with my Heart", [flagship_store, new_installment])
biz2 = Business("Take a' Arepa", arepas_place)


print (brunch)
print (brunch.items)
print (early_bird)
print (kids)
print (dinner)
print(brunch.calculate_bill(['pancakes','home fries']))
print(early_bird.calculate_bill(['salumeria plate','mushroom ravioli (vegan)']))
print(flagship_store)
flagship_store.available_menus(12)
flagship_store.available_menus(17)

  
2 Likes

Hello @codeitcodeitgood,

You may be able to make some of the code more efficient. For instance, consider whether it is really necessary to use a nested loop in the calculate_bill method of Menu.

Edited on July 1, 2020 to add the following:

You can loop through the keys in purchased_items. Within the loop, use each key to get the price of the item, and append that price to bill.

2 Likes

Thank you for your response. Maybe something like this?:

 def calculate_bill(self, purchased_items):
    self.purchased_items = purchased_items
    bill= 0
    for y in purchased_items:
      bill += self.items[y]
    return bill

That looks good, but what does this line do?

1 Like

I removed the line and found the method works effectively without it. I was under the impression that variables used in Class constructors and methods require using the “self” parameter… Perhaps this is true only for the init constructor itself?

Basically, yes. The __init__ method/constructor is used to initialize new instances of the class. This is where the class instances’ attributes are defined. Your calculate_bill method accepts a parameter called purchased_items which can be accessed inside the method, as you’ve seen, just like any function has access to its parameters.

2 Likes

Thank you for your assistance. This is all very new to me. I was recently released from prison in Florida and am adjusting. I didn’t hurt anyone, I just destroyed a bunch of property. I only did a nickel, but it’s amazing how much the world changes in 5 years.

2 Likes

You’re welcome.

1 Like

Hello @codeitcodeitgood,

Best of luck to you for a good future.

To aid a discussion about instructional material, it is generally a good idea to provide a link to that material, so here it is:

With the nested loop and the unnecessary assignment statement removed, you now have a good calculate_bill method for the Menu class.

Edited on July 1, 2020 to clarify the following suggestion:

Regarding the nested loops, you can make a similar improvement to the available_menus method in the Franchise class. If you revise that method and post it, we can take a look at it.

2 Likes

Thank you - I need all the good luck I can get. Had more than my share of the other kind. Regarding the nested loops, I’m not seeing it. The menus in available_menus are all dictionaries. So I can’t determine how to parse the dictionary without referencing the keys and values separately.

Let’s first note that to create an instance of Franchise, we do something like this:

flagship_store = Franchise("1232 West End Road", [brunch, early_bird, dinner, kids])

The final argument in that line of code is this list of Menu instances:

[brunch, early_bird, dinner, kids]

Also note that the final line in the __init__ method of Franchise is:

    self.menus = menus

That line assigns the list of Menu instances that we provide when we create a Franchise instance to an instance variable named menus. So, to access that list within a method of the Franchise class, we would refer to it as self.menus, assuming that we are following the convention of using self to refer to the current instance. That is what you are doing in this line of code in the available_menus method of Franchise:

    for menu in self.menus:

With each iteration of the loop, menu will reference one of the Menu instances from the list. You test it with this line of code to find out if it is available at the specified time:

        if time >= menu.start_time and time <= menu.end_time:

If the condition is True, all you need to do is append the object referred to as menu to menulist. No intervening action is necessary. You do not need this inner loop header:

          for keys in menu.items:

You only need to do this:

          menulist.append(menu)
1 Like

I get it now - this instruction confused me:

" Let’s tell our customers what they can order! Give Franchise an .available_menus() method that takes in a time parameter and returns a list of the Menu objects that are available at that time."

By ‘Menu’ objects I thought they were referring to Menu items (from the Menu class). I didn’t realize the method’s purpose was just to list the available menus at a given time. Rather, I figured they wanted a list of dishes available. I have a tendency to overcomplicate things. Thank you for the explanation.

2 Likes

I see everyone one doing this but wonder why use the logic like that instead of

if menu.start_time <= time <= menu.end_time:

Is there a use-case where one works over the other?

1 Like

Hi @coreblaster01537,

The two lines you posted are equivalent. It may be that most users are more familiar with the and operator than with the chaining of comparison operators.

1 Like

Your code actually helped me figure out the calculate_bill portion of the Menu class. I kept getting confused as to how I was supposed to access the items in a given menu to add the selected ones to the bill. Turns out, the fact that we’re instructed to call them “items” in the Menu class’ init parameters was making me confuse the “items” parameter with the “items()” method while I was trying to put together the code.

Since the projects allow us a lot more wiggle room with how we code (e.g. they don’t block us from advancing to the next step by calling our work incorrect if we don’t name a parameter/variable/etc. EXACTLY what the instructions say to name them), I amended this by changing the name of the “items” parameter to “meals”. I know it feels like more of a cosmetic change than anything else, but it helped me differentiate the terms better.

@midlindner and @appylpye , if I may make a small suggestion: You might consider passing along to the lesson/project instructions writers that it may make things a little easier to understand if they change the instructions so that we don’t end up giving parameters names that overlap with built-in default methods and functions of the Python language (for example, instead of calling it the “items” parameter, they could have us call it “meals” or “dishes”).

Sorry for bumping this old thread, but I just wanted to express my appreciation for the help it provided me and offer a suggestion to improve the project instructions a bit.

How do I calculate for two pancakes instead of one ?
print(brunch_menu.calculate_bill([‘pancakes’, ‘home fries’, ‘coffee’ *2 ]))
output: 12

print(brunch_menu.calculate_bill([‘pancakes’, ‘home fries’, ‘coffee’]))
output: 13.5

Hi! I would like to know why I get 0 instead of 13.5
class Menu:
def init(self, name, items, start_time, end_time):
self.name = name
self.items = items
self.start_time = start_time
self.end_time = end_time

def repr(self):
return self.name + " is available from " + str(self.start_time) + " - " + str(self.end_time) + “.”

def calculate_bill(self, purchased_items):
bill = 0
for purchased_item in purchased_items:
if purchased_item is self.items:
bill += self.items[purchased_item]
return bill

brunch_items = {
‘pancakes’: 7.50, ‘waffles’: 9.00, ‘burger’: 11.00, ‘home fries’: 4.50, ‘coffee’: 1.50, ‘espresso’: 3.00, ‘tea’: 1.00, ‘mimosa’: 10.50, ‘orange juice’: 3.50
}

early_bird_items = {
‘crostini with eggplant caponata’: 13.00, ‘caesar salad’: 16.00, ‘pizza with quattro formaggi’: 11.00, ‘duck ragu’: 19.50, ‘mushroom ravioli (vegan)’: 13.50, ‘coffee’: 2.00, ‘espresso’: 3.00
}

dinner_items = {
‘crostini with eggplant caponata’: 13.00, ‘caesar salad’: 16.00, ‘pizza with quattro formaggi’: 11.00, ‘duck ragu’: 19.50, ‘mushroom ravioli (vegan)’: 13.50, ‘coffee’: 2.00, ‘espress’: 3.00
}

kids_items = {
‘chicken nuggets’: 6.50, ‘fusilli with wild mushrooms’: 12.00, ‘apple juice’: 3.00
}

brunch_menu = Menu(‘Brunch’, brunch_items, 1100, 1600)
early_bird_menu = Menu(‘Early Bird’, early_bird_items, 1500, 1800)
dinner_menu = Menu(‘Dinner’, dinner_items, 1700, 2100)
kids_menu = Menu(‘Kids’, kids_items, 1100, 2100)

print(brunch_menu.calculate_bill([‘pancakes’, ‘home fries’, ‘coffee’]))

Expected value is 13.5 but I get 0.