Restaurant Modeler
Last updated
Last updated
In this exercise, we will be modeling a real-world scenario, a restaurant app that will be simulating restaurants and a bakery in New York City's Boroughs:
We will first be creating our first class Restaurant() in which we also be creating multiple attributes like, name
, cuisine
, location
, and methods such as restaurant_type
and restaurant_location
. Here is our base code:
The __init__
method defined as the first function is a special method, and Python runs it whenever we create a new instance based on the class. The use of two underscore before and after the name 'init' is a convention and prevents default Python method names from conflicting with user defined method names.
there are 4 parameters defined in the __init__
method:
self
name
cuisine
location
Note that capacity
parameter is not among he method parameters. This is on purpose and to show how we can add default attributes to the classes.
self
is required in the method definition, and comes first before all other parameters. It enables individual instance access to the methods and the attributes in the class. When we create an instance of the class, it is passed automatically, so doesn't require manual entry. We provide values only for other parameters defined in the method. Any variable with the self
prefix is available to every method in the class.
Also, notice that not all the attributes come from the parameters such as capacity
. Because it is not required parameter like others. Here we defined an attribute with a default value that can be accessed with a call to that attribute or get updated it with a method. This is a very useful feature since we might want to assign certain default values to attributes and not to require manual entry from the user.
Let's see some examples. We will be creating 5 instances of the Restaurant class below each of which has different values.
Note that for Restaurant 4 we used the print
function to be able to display the description since the get_description
method returns only a variable called rest_desc
and does not have a print
statement.
In addition, for Restaurant 5, we have updated the default restaurant capacity
(from 30 to 12) first and then called the restaurant_capacity
method to show the number of people can the restaurant accommodate.
Now let s add an attribute named patrons_served
with a default value 0:
Time to create an instance, call it res6
of our Restaurant class and call the attribute patrons_served
:
Not let us create another method, called update_patrons
to update the number of customers the Restaurant has served for a given time on a day:
We call the method set_patrons
with a value of 26 and recall the patrons_served again we get the updated the patron count:
Not let us add functionally to increase the number of customers served with a method called increase_patrons
:
When we call the method with previous instance:
If we are working on a class that is sort of a version of class we worked on before, we can use what is called Inheritance to adopt all methods and attributes of the original class. By convention, the original class if called the parent class, and the new class we are creating is called the child class.
To be able use all the features a parent class offers we need to pay attention to the 2 points:
Child class wraps around the parent class in the definition:
class Child (Parent):
super()
function used with the __init__
method
Let us create a special type of restaurant class, Bakery, to our script and inherit all features Restaurant, the parent class, has:
Since we created our new class, Bakery, it is time to create an instance and call some of the methods it inherited from the Restaurant class:
Output:
The methods work perfectly with only one minor issue: a bakery is a type of a restaurant but NOT a restaurant. Let's solve this by updating our code, with an attribute similar to capacity
and patrons_count
, and called category
in our parent class Restaurant with a set value restaurant, replace all 'Restaurant' statements with it in all print statements, and finally overwrite it in our child class, Bakery:
Now, if we call the methods on our bakery instance, we will get the desired outcome:
Output:
As we can see there is no limit to the number of methods or attributes we can add to a class. However, adding multiple methods and attributes may result in complicated scripts and make things more difficult than easier. For instance, let us say we would like to add create a coffee menu instance for our bakery which can easily be done as we seen above. However, we when think about it a coffee, it has multiple attributes like type, size, extras, etc. This might complicate our Bakery class considering other attributes and methods the class has. Therefore, it will be better if we create another class only for coffees, and add its instances as attributes. In the following example, we create a class called Coffee
and add it to the Bakery class as an attribute called coffee
.
We can now access to all Coffee class methods and attributes from the Bakery's coffee
attribute:
Output:
Breakdown of the new lines
print(bakery.coffee.coffee)
tells python to look at the instance bakery, find its coffee
attribute and find the coffee
attribute that is associated Coffee
instance with the and print it
print(bakery.coffee.size)
similarly tells python to look at the instance bakery, find its coffee
attribute and find the size
attribute attribute that is associated Coffee
instance and print it
bakery.coffee.get_coffee_description(
) like the others above first tells python to look at the instance bakery, find its coffee attribute and call the get_coffee_description()
that is associated with the Coffee instance stored in the attribute
Once we complete our classes, it is time to save our work. Different from regular scripts
, ie. python files that consist of our codes, the scripts that include classes are called modules
, aka packages or libraries. We will save our module as restaurant.py
. Our module has three classes:
Restaurant()
Coffee()
Bakery()
Once we save our module, importing it or some of its classes is no different than importing your favorite modules/packages such as numpy
or pyplot
from matplotlib library.
In a separate python file, called my_favorite_places.py
, we will import Restaurant class and create instances from that class.
We can in practice import as many classes as we need. Let's say we want to create a restaurant and a bakery in the same script, we then need to import the classes Restaurant and Bakery:
Output:
We can also simply import all the classes using '*' and create instances of classes as we did above:
If we need to use many classes then it is better to import the entire module. In this case, we will need to use dot notation to access the classes:
Output:
Congratulations! With this, we have finished our OOP practice! You might now think that you would create certain methods or classes differently, and I would say you are absolutely right! As stated above, our options are limitless on how we model real-world cases. Most of the cases, there are no right or wrong approaches to modeling. It is all about efficiency and it comes with experience. The more we are modeling real 'objects' the more efficient we will become.