Learn Python: Classes: Basta Fazoolin'


#1

https://www.codecademy.com/paths/computer-science/tracks/cspath-python-objects/modules/cspath-python-classes/projects/basta-fazoolin
from datetime import datetime, time
current_time=datetime.now()
print(current_time)

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 "Menu {} available at {}:00 to {}:00".format(self.name, self.start_time, self.end_time)
  def calculate_bill(self, purchased_items):
    self.purchased_items=purchased_items
    total_price=0
    for i in self.purchased_items:
      total_price+=self.items[i]
      print(i)
    return total_price
class Franchise(Menu):
  def __init__(self, address, menus):
    self.address = address
    self.menus = menus
  def __repr__(self):
    return self.address
  def available_menus(self,time):
    self.time=time
    for i in self.menus:
      if self.time >= self.start_time and self.time<self.end_time:
        print(i)

flagship_store = Franchise("1232 West End Road",[brunch, early_bird, dinner, kids])
new_installment = Franchise("12 East Mulberry Street", [brunch, early_bird, dinner, kids])
print(flagship_store.available_menus(time(12, 00)))

So when I run I get this File “script.py”, line 43, in available_menus if self.time >= self.start_time and self.time<self.end_time: AttributeError: ‘Franchise’ object has no attribute ‘start_time’
how I can use self.strat_time and self.end_time from Menu class?
I try make this part : 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.


#2

user super() to call the parent __init__() method.

you gave Franchise an init method, so when create a instance of Franchise, the init method of Franchise gets called, not the init method of Menu. (method overwriting in essence)


#3
from datetime import datetime, time
current_time=datetime.now()
print(current_time)

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 "Menu {} available at {}:00 to {}:00".format(self.name, self.start_time, self.end_time)
  def calculate_bill(self, purchased_items):
    self.purchased_items=purchased_items
    total_price=0
    for i in self.purchased_items:
      total_price+=self.items[i]
      print(i)
    return total_price
class Franchise(Menu):
  def __init__(self, address, menus):
    super().__init__(name, items, start_time, end_time)
    self.address = address
    self.menus = menus
  def __repr__(self):
    return self.address
  def available_menus(self,time):
    for i in self.menus:
      if self.time >= self.start_time and self.time<self.end_time:
        print(i)  
flagship_store = Franchise("1232 West End Road",[brunch, early_bird, dinner, kids])

Now I need do define ‘name’ but I already make it in Menu class, if I am make it right of course.

Traceback (most recent call last):
_ File “script.py”, line 31, in _
_ flagship_store = Franchise(“1232 West End Road”,[brunch, early_bird, dinner, kids])_
_ File “script.py”, line 22, in init_
_ super().init(name, items, start_time, end_time)_
NameError: name ‘name’ is not defined


#4

i am kind of puzzled how the instructions want to have this

the problem is here:

class Franchise(Menu):
  def __init__(self, address, menus):
    super().__init__(name, items, start_time, end_time)

name doesn’t exist within the init method

you need to pass name, items, start_time and end_time as parameters to init, which means you need to provide all this information when creating Franchise instance. I am kind of puzzled


#5

i am currently quickly running through the project, will get back to you ASAP.


#6

Yes but i’s not what I need to do in my Tasks:
12. First, let’s create a Franchise class.
13. Give the Franchise class a constructor. Take in an address , and assign it to self.address . Also take in a list of menus and assign it to self.menus .

class Franchise():
  def __init__(self, address, menus):
    self.address = address
    self.menus = menus
  1. Let’s create our first two franchises! Our flagship store is located at "1232 West End Road" and our new installment is located at "12 East Mulberry Street" . Pass in all four menus along with these addresses to define flagship_store and new_installment .
flagship_store = Franchise("1232 West End Road",[brunch, early_bird, dinner, kids])
new_installment = Franchise("12 East Mulberry Street", [brunch, early_bird, dinner, kids])
  1. Give our Franchise s a string represenation so that we’ll be able to tell them apart. If we print out a Franchise it should tell us the address of the restaurant.
def __repr__(self):
    return self.address
  1. 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.
 def available_menus(self,time):
    for i in self.menus:
      if self.time >= self.start_time and self.time<self.end_time:
        print(i)      
  1. Let’s test out our .available_menus() method! Call it with 12 noon as an argument and print out the results.
#print(flagship_store.available_menus(time(12, 00)))

So as you can see I am shouldn’t create a new instance of Franchise with additional parameters I need figure it out How I can use this parameters from object Menu

current_time=datetime.now()
print(current_time)

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 "Menu {} available at {}:00 to {}:00".format(self.name, self.start_time, self.end_time)
  def calculate_bill(self, purchased_items):
    self.purchased_items=purchased_items
    total_price=0
    for i in self.purchased_items:
      total_price+=self.items[i]
      print(i)
    return total_price
class Franchise():
  def __init__(self, address, menus):
    self.address = address
    self.menus = menus
  def __repr__(self):
    return self.address
  def available_menus(self,time):
    for i in self.menus:
      if self.time >= self.start_time and self.time<self.end_time:
        print(i)      
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}
brunch=Menu("brunch", brunch_items, time(11, 00), time(16, 00))  
early_bird_items={'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}
early_bird = Menu("early_bird", early_bird_items,time(15, 00), time(18, 00))
dinner_items={'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,}
dinner = Menu("dinner", dinner_items, time(17,00), time(23, 00)) # I need to use this object 
kids_items={'chicken nuggets': 6.50, 'fusilli with wild mushrooms': 12.00, 'apple juice': 3.00}
kids=Menu("kids", kids_items,time(11, 00), time(21, 00))
print(brunch.calculate_bill(['pancakes', 'home fries', 'coffee']))
print(early_bird.calculate_bill(['salumeria plate', 'mushroom ravioli (vegan)']))
print(dinner)

        
flagship_store = Franchise("1232 West End Road",[brunch, early_bird, dinner, kids])
new_installment = Franchise("12 East Mulberry Street", [brunch, early_bird, dinner, kids])
print(flagship_store.available_menus(time(12, 00)))

#7

each menu:

def available_menus(self,time):
   for i in self.menus:
     print(i)

which you named i, contains there start_time and end_time, you can access them

i is not a descriptive variable, i would use something more logic like menu


#8

for example

def available_menus(self,time):
    for i in self.menus:
      if i is "17:00:00:00" and i is "23:00:00:00":
        print(i)      

how I can compare time objects which represented like str ?
what operator I should use?
when I print I get None


#9

i wouldn’t use strings, that sounds like a terrible idea. I would use the time() function you imported:

brunch = Menu("brunch", items.brunch_items, time(11, 0), time(16, 0))

and then in the method call to available menus:

flagship_store.available_menus(time(17, 15))

then we can use simple greater and lesser then comparison operators to compare time with the i.start_time and i.end_time

sorry for putting you on the wrong foot at the beginning, where i thought init need modifications.


#10

what i did was creating a new file (items.py), there i dumped all the dictionaries:

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 = {
  '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,
}
dinner_items = {
  '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,
}
kids_items = {
  'chicken nuggets': 6.50, 
  'fusilli with wild mushrooms': 12.00, 
  'apple juice': 3.00
}

then in script.py i imported all the dictionaries:

import items

and used them when creating the instances:

brunch = Menu("brunch", items.brunch_items, time(11, 0), time(16, 0))
early_bird = Menu("early_bird", items.early_bird_items, time(15, 0), time(18, 0))
dinner = Menu("dinner", items.dinner_items, time(17, 0), time(23, 0))
kids = Menu("kids", items.kids_items, time(11, 0), time(21, 0))

this just cleans up the code a lot.

it massively improved readability. I can highly recommend you to do the same.


#11

Instruction 16 actually asks that the .available_menus() method return a list of the Menu objects, rather than print them directly …

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.

The instruction that follows asks that the user print out the results.

The distinction between printing and returning a result may seem minor, but returning a result does allow for the programmer to perform additional processing of a result after the function has been called, if desired. This provides more flexibility, for example, in this case, more choices in how to display the menus.


#12

Tell me please how you make pairs of( keys and values) of the dictionaries in individual rows?

def available_menus(self,time):
    self.time=time
    for i in self.menus:
      if self.time >= i.start_time and self.time < i.end_time:
        return i

#13

You placed this in the loop …

        return i

Therefore, it executes during the first iteration, and you only see one item.

Instead, accumulate the results in a list, then return that list after the loop.


#14
 def available_menus(self,time):
    self.time=time
    list_of_available_menus=[]
    for i in self.menus:
      if self.time >= i.start_time and self.time < i.end_time:
        list_of_available_menus.append(i)
    return list_of_available_menus
print(flagship_store.available_menus(time(12, 00)))
print(flagship_store.available_menus(time(17, 00)))

#15

That looks good. Since you returned the results, you could do a fancier thing with the output, if you want, such as this …

flagship_avail = flagship_store.available_menus(17)
print("\nAvailable now!")
for menu in flagship_avail:
  print("-> {}".format(menu))

Output …

Available now!
-> Early Bird available from 15:00 to 18:00
-> Dinner available from 17:00 to 23:00
-> Kids available from 11:00 to 21:100:

Using return instead of print in the method has gained us some flexibility.


#16

Thank you a lot!
Tell me please how you make time without additional 00:00? because I see it like :
Menu early_bird available at 15:00:00:00 to 18:00:00:00
datetime.strptime()?


#17

Here’s my __repr__ method for Menu

  def __repr__(self):
    return "{} available from {}:00 to {}:00".format(self.name, self.start_time, self.end_time)

I have my times stored as ints between 0 and 23, inclusive.

You can refine that __repr__ method, so that it represents a Menu instance as you like.


#18
import items
from datetime import datetime, time
current_time=datetime.now()
print(current_time)

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 "Menu {} available at {}:00 to {}:00".format(self.name, self.start_time, self.end_time)
  def calculate_bill(self, purchased_items):
    self.purchased_items=purchased_items
    total_price=0
    for i in self.purchased_items:
      total_price+=self.items[i]
      print(i)
    return total_price
class Franchise():
  def __init__(self, address, menus):
    self.address = address
    self.menus = menus
  def __repr__(self):
    return self.address
  def available_menus(self,time):
    self.time=time
    list_of_available_menus=[]
    for i in self.menus:
      if self.time >= i.start_time and self.time < i.end_time:
        list_of_available_menus.append(i)
    return list_of_available_menus
  
brunch=Menu("brunch", items.brunch_items, time(11, 00), time(16, 00))  

early_bird = Menu("early bird", items.early_bird_items,time(15, 00), time(18, 00))

dinner = Menu("dinner", items.dinner_items, time(17,00), time(23, 00))

kids=Menu("kids", items.kids_items,time(11, 00), time(21, 00))
arepas_menu = Menu("Take a' Arepa", items.arepas_menu_items, time(10), time(20))
    
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", [brunch, early_bird, dinner, kids, arepas_menu])

class Business():
  def __init__(self, name, franchises):
    self.self=self
first = Business("Basta Fazoolin with my Heart",[flagship_store, new_installment])
new_business = Business("Take a' Arepa",[flagship_store, new_installment, arepas_place] )

please check this out do I Make it right?
19. Since we’ve been so successful building out a branded chain of restaurants, we’ve decided to diversify. We’re going to create a restaurant that sells arepas!

First let’s define a Business class.

  1. Give Business a constructor. A Business needs a name and a list of franchises .

  2. Let’s create our first Business . The name is "Basta Fazoolin' with my Heart" and the two franchises are flagship_store and new_installment .

22.Before we create our new business, we’ll need a Franchise and before our Franchise we’ll need a menu. The items for our Take a’ Arepa available from 10am until 8pm are the following:

{
  'arepa pabellon': 7.00, 'pernil arepa': 8.50, 'guayanes arepa': 8.00, 'jamon arepa': 7.50
}

Save this to a variable called arepas_menu .

  1. Next let’s create our first Take a’ Arepa franchise! Our new restaurant is located at "189 Fitzgerald Avenue" . Save the Franchise object to a variable called arepas_place .

  2. Now let’s make our new Business ! The business is called "Take a' Arepa" !


#19

Did you add the arepas_menu_items information to the items.py file?

In the __init__ method for Business, you didn’t do anything with the franchises parameter. You should have something similar to this, so that the information is saved in an instance variable …

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

The __repr__ method is extra, but it seemed a good idea to provide one.

How does your output look?


#20

I’ve still only got to step 8 and then segued into a bit of silliness…

class Half_time(object):
  def __init__(self, hour):
    self.hour = "{}:00 {}".format(hour % 12, ['AM', 'PM'][hour > 12])
  def __repr__(self):
    return self.hour
  
class Menu(object):
  def __init__(self, name, items, start_time, end_time):
    self.name = name
    self.items = items
    self.start_time = Half_time(start_time)
    self.end_time = Half_time(end_time)
  def __repr__(self):
    return "{} menu available {} to {}\n\n{}".format(self.name, self.start_time, self.end_time, self.pretty_print())
  def pretty_print(self):
    s = ""
    for k, v in self.items.items():
      s += "{:<40} {:6.2f}\n".format(k, v)
    return s

The Half_time class takes nautical time (hour only) and converts to conventional time. Each instance is a formatted string.

pretty_print returns a formatted string containing linebreaks.

Sample output

Dinner menu available 5:00 PM to 11:00 PM

duck ragu                                 19.50
crostini with eggplant caponata           13.00
mushroom ravioli (vegan)                  13.50
pizza with quattro formaggi               11.00
coffee                                     2.00
ceaser salad                              16.00
espresso                                   3.00