12/April - Object-oriented Python
Prerequisites
- You have completely set up one of the three Python development options
- You have solved the tasks from the last class
Class Curriculum
Section content | Expected time (mins) | Pre - Requirements |
---|---|---|
Lesson Goals | 5 minutes | ❌ |
Check-in on pre-reqs and questions from last class | 15 minutes | ❌ |
Procedural programming | 10 minutes | ❌ |
Object-oriented Programming | 10 minutes | ❌ |
Pillars of object-oriented programming | 10 minutes | ❌ |
Break | 10 minutes | ❌ |
Task: Extend the pet clinic example | 20 minutes | ❌ |
Bonus Task: Implement a REDI Course Management System | 20 minutes | ❌ |
Check-out | 10 minutes | ❌ |
0. Lesson Goals
- Learn the difference between procedural vs. object-oriented programming.
- Learn the pillars of object-oriented programming in Python
- Classes
- Objects
- Constructor functions
- Object Methods
- Inheritance
1. Check-In
- What was particularly challenging last class? Are there any remaining questions from last class?
- What exercises were the most challenging? (Respond in the chat)
2. Procedural Programming
Procedural programming involves writing sequential code which is executed from top to the bottom of the file. You are not allowed to switch steps otherwise the program will fail to run. You can think of procedural programming like the process of boiling some spaghetti.
- You get a clean pot
- You pour some water into the pot
- You switch on the cooker
- You wait for the water to start boiling
- You add the Spaghetti
- You add some salt
- You wait for about 10 to 15 minutes for the Spaghetti to cook
Here are some characteristics of procedural programming:
- In procedural programming, program is divided into small parts called functions.
- Procedural programming follows top down approach.
- Adding new data and functions is not easy.
- Procedural programming does not have any proper way for hiding data so it is less secure.
- In procedural programming, function is more important than data.
- Procedural programs are not modelled according to real-world structure.
- Procedural programming languages include C, FORTRAN, Pascal, Basic etc
3. Object-Oriented Programming
Object-oriented programming involves writing code in terms of the objects that make up the problem you are trying to solve. The definitions of these objects in the code can be switched around without causing the program to fail. You can think of object-oriented programming like the process of solving a jigsaw puzzle.
Here are some characteristics of object-oriented programming:
- In object-oriented programming, the program is divided into small parts called objects.
- Object-oriented programming follows bottom up approach.
- Adding new data and function is easy.
- Object-oriented programming provides data hiding so it is more secure.
- In object-oriented programming, data is more important than function.
- Object-oriented programs are modelled according to real-world structure.
- Object-oriented programming languages include C++, Java, Python, C# etc.
4. Pillars of Object-Oriented Programming in Python
Classes
Classes represent a group of objects you would like to manage in your program. Classes in python are declared as follows:
1class class_name:
2 class_body
For example if you are writing code to manage the pets at a pet clinic then your program is managing different pets, whether they are
dogs, cats, turtles etc. In your program you would represent all these different breeds using a Pet
class.
1class Pet:
2 pass
pass
keyword is used when we do not want to specify any details of the class.
Objects
When we define a class only the description or a blueprint of all possible objects defined by that class is created. For example one particular cat at the pet clinic is an object of the Pet class. When you create an object from a class in your code, you assign it to a variable to allow you do something meaningful with that specific object. You create an object and assign it to a variable as follows:
1object_variable = class_name()
For example, an object for a cat called Maya
can be created from the Pet
class as follows:
1maya = Pet()
Now you can print the Maya
object
1print(maya)
2# outputs something like -> <__main__.Pet object at 0x7ff41e9bcdd0>
0x7ff41e9bcdd0
above is the address of Maya
in memory on my computer. The value will be different on your computer
Constructor functions
The examples above are classes and objects in their simplest form, and are not really useful in real life applications.
To understand the meaning of classes we have to understand the built-in __init__()
constructor function.
All classes have a function called __init__()
, which is always executed when an object of the class is being constructed.
Use the __init__()
function to assign values to object properties, or other operations that are necessary to do when the object is being created:
For example, in the example from above
1maya = Pet()
We know that object relates to a cat called Maya
because we stored the object in a variable called maya
.
Now consider if we instead named the variable differently:
1pet_one = Pet()
We've lost all hints that the pet_one
object actually refers to Maya
. We can add a constructor function to the Pet
class which will allow us to give names to pets objects we create.
1class Pet:
2 def __init__(self, name):
3 self.name = name
With the new constructor function added to the Pet
class, we can now create pet objects with actual names
1pet_one = Pet("Maya")
2pet_two = Pet("Felix")
And we can selectively print the names of each pet
1print(pet_one.name)
2print(pet_two.name)
3# outputs
4# Maya
5# Felix
Object Methods
Objects can also contain functions called Methods
. Methods allow the program to perform actions on objects.
Let us add a hello
method to the Pet
class that the pets can use to introduce themselves (if they could speak)
1class Pet:
2 def __init__(self, name):
3 self.name = name
4
5 def hello(self):
6 print("Hello my name is " + self.name)
Now we can create a pet called called Maya
and have her say hello!
1pet_one = Pet("maya")
2pet_one.hello()
3# output -> Hello my name is maya
Class inheritance
Inheritance allows us to define a class that is a sub-category of another class. For example at the pet clinic, we have
a Pet
class. But using the Pet
class, we cannot differentiate between cats, dogs, turtles or birds.
We can create new classes for the different kinds of animals at the pet clinic and have all of them inherit from the Pet
class.
1class Pet:
2 def __init__(self, name):
3 self.name = name
4
5 def hello(self):
6 print("Hello my name is " + self.name)
7
8class Cat(Pet):
9 pass
10
11class Dog(Pet):
12 pass
13
14class Turtle(Pet):
15 pass
16
17class Bird(Pet):
18 pass
The Pet
class is known as the parent class.
The Cat
, Dog
, Turtle
and Bird
classes are known as child class.
Now we can create more pet objects using their specific classes and they will all be able to say hello
because they've inherited
the hello method from the Pet
class
1cat_one = Cat("maya")
2dog_one = Dog("bosco")
3turtle_one = Turtle("speedy")
4bird_one = Bird("diver")
5
6cat_one.hello()
7dog_one.hello()
8turtle_one.hello()
9bird_one.hello()
10
11# outputs
12# Hello my name is maya
13# Hello my name is bosco
14# Hello my name is speedy
15# Hello my name is diver
Even though we now have various child classes of the parent class Pet
, each of those child classes have characteristics
that apply to only them. For example cats can meow, dogs can bark, birds can fly and turtles can hide in their shell.
We can add more specific class methods into the various child classes to provide more specific behaviors.
Lets add:
- A
meow
method to theCat
class which causes the cat to make the meow sound - A
bark
method to theDog
class which causes the cat to bark - A
fly
method to theBird
class which causes the bird to fly - A
hide
method to theTurtle
class which causes the turtle to go into its shell
1class Pet:
2 def __init__(self, name):
3 self.name = name
4
5 def hello(self):
6 print("Hello my name is " + self.name)
7
8class Cat(Pet):
9 def meow(self):
10 print("Meeeeeooooww! I am a cat!")
11
12class Dog(Pet):
13 def bark(self):
14 print("Wooof! Woof! I am a dog!")
15
16class Turtle(Pet):
17 def hide(self):
18 print("Hide! I'm shy! I am a turtle!")
19
20class Bird(Pet):
21 def fly(self):
22 print("Swoooosh! I'm flying away! I am a bird!")
Now lets get all our pets to first say hello and then perform the actions they are good at
1cat_one = Cat("maya")
2dog_one = Dog("bosco")
3turtle_one = Turtle("speedy")
4bird_one = Bird("diver")
5
6cat_one.hello()
7cat_one.meow()
8
9dog_one.hello()
10dog_one.bark()
11
12turtle_one.hello()
13turtle_one.hide()
14
15bird_one.hello()
16bird_one.fly()
17
18# outputs
19# Hello my name is maya
20# Meeeeeooooww! I am a cat!
21# Hello my name is bosco
22# Wooof! Woof! I am a dog!
23# Hello my name is speedy
24# Hide! I'm shy! I am a turtle!
25# Hello my name is diver
26# Swoooosh! I'm flying away! I am a bird!
Small challenge : "It's almost Easter..."
In this exercise, we will try to create a small game using Object Oriented Programming. It is still possible not to use classes, but you will see that it complicates the code considerably... The ultimate goal of this challenge is to show you the power of classes !
The game : context & rules
Every year, in a small rural village, the municipality organizes a treasure hunt. Many sweets are hidden in the town and the participants have to find them within a given time. The one who finds the most sweets wins the game. Let's code this.
The slides available here give you a better understanding of how the game will be run.
Here is the code that simulate the game, the goal is to reimplement this code by using classes.
1from random import randrange
2
3
4def update_challenger_points(challenger, world):
5 """
6
7 Desc : tells whether the challenger wins a point. If yes it modifies the number of points.
8 Params : world, challenger
9 Return : None
10
11 """
12 if world[challenger['position']] == 1:
13 challenger['collected_treasures'] += 1
14
15
16def set_challenger_mood(challenger, new_mood):
17 """
18
19 Desc : sets the mood of the challenger
20 Params : challenger, new_mood
21 Return : None
22
23 """
24 challenger['mood'] = new_mood
25
26
27def set_challenger_position(challenger, new_pos):
28 """
29
30 Desc : sets the mood of the challenger
31 Params : challenger, new_mood
32 Return : None
33
34 """
35 challenger['position'] = new_pos
36
37
38
39def update_challenger_position(challenger, world):
40 """
41
42 Desc : gives the new box number where the challenger has to go + sets the new position of the challenger
43 Params : challenger, world
44 Return : the new given position
45
46 """
47 square_number = randrange(len(world)) # HINT : randrange is a method from the 'random' library. It gives an integer between 0 and len(world).
48 set_challenger_position(challenger, square_number)
49 return square_number
50
51
52def print_challenger(challenger):
53 """
54
55 Desc : return the relevant information of the challenger when programmers use 'print'
56 Params : challenger
57 Return : the name of the challenger
58
59 """
60 print(challenger['name'])
61
62
63def interview_challengers_podium(sport_commentator, challengers):
64 """
65
66 Desc : interviews the first three challengers and asks them their mood after the competition. The answer of this question is printed.
67 Params : challengers
68 Return : the list of moods in the same order than the ranking
69
70 """
71 # TO BE COMPLETED
72 pass
73
74
75def announce_challengers(sport_commentator, challengers):
76 """
77
78 Desc : announces(print) the challenger
79 Params : challengers
80 Return : True
81
82 """
83 print("[{}]:'The name of the challenger number one is {}'".format(sport_commentator['name'], challengers[0]['name']))
84 print("[{}]:'The name of the challenger number one is {}'".format(sport_commentator['name'], challengers[1]['name']))
85 print("[{}]:'The name of the challenger number one is {}'".format(sport_commentator['name'], challengers[2]['name']))
86 print("[{}]:'The name of the challenger number one is {}'".format(sport_commentator['name'], challengers[3]['name']))
87 # TO BE REFACTORED (use a for...loop that depends dynamicaly on the number of challengers)
88 return 1
89
90
91def annouce_winner(sport_commentator, winner):
92 """
93
94 Desc : announces the winner
95 Params : challengers
96 Return : True
97
98 """
99 print("[{}]:'And the winner is {}'".format(sport_commentator['name'], winner['name']))
100 return True
101
102
103def find_winner(challengers):
104 """
105
106 Desc : finds the challenger who has collected the most treasure and prints and returns the winner
107 Params : challengers
108 Return : the winner (as an object)
109
110 """
111 # TODO : case when there is a draw
112 hyp_winner = challengers[0]
113 for challenger in challengers:
114 if challenger['collected_treasures'] > hyp_winner['collected_treasures']:
115 hyp_winner = challenger
116 return hyp_winner
117
118
119
120
121
122if __name__ == '__main__':
123
124 # Part one : data definition
125 moods = ["happy", "anxious", "impatient", "desappointed", "amazed"]
126
127 # Note to the programmer : if you want to add challengers to the game you must follow the following rules :
128 # a challenger is a challenger IF AND ONLY IF he/she has a name, an age, a mood, a position and a collected_treasures
129
130 challenger_1 = {'name': "Antoine", 'age': 23, 'mood': moods[0], 'position': 0, 'collected_treasures': 0}
131 challenger_2 = {'name': "Thomas", 'age': 18, 'mood': moods[1], 'position': 0, 'collected_treasures': 0}
132 challenger_3 = {'name': "Julia", 'age': 28, 'mood': moods[0], 'position': 0, 'collected_treasures': 0}
133 challenger_4 = {'name': "Richard", 'age': 40, 'mood': moods[2], 'position': 0, 'collected_treasures': 0}
134
135 challengers = [challenger_1, challenger_2, challenger_3, challenger_4]
136
137 sport_commentator = {'name': "Kathrine", 'age':68 }
138
139 world_2D = [0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1]
140
141 n_turns = 8
142
143 # Part two : game execution
144 announce_challengers(sport_commentator, challengers)
145
146 print("The game is starting...")
147
148 for turn_index in range(n_turns):
149 for challenger in challengers:
150 update_challenger_position(challenger, world_2D)
151 update_challenger_points(challenger, world_2D)
152
153 winner = find_winner(challengers)
154 annouce_winner(sport_commentator, winner)
155
156
157 for challenger in challengers:
158 if challenger == winner:
159 set_challenger_mood(challenger, moods[4])
160 else:
161 set_challenger_mood(challenger, moods[3])
162
163 interview_challengers_podium(sport_commentator, challengers)
Guide lines and TODO:
First step : work only with the story
- With the help of the slides, write down any kind of entities you can find in the story.
- Try to draw links between entities. Can you say that some entities belongs to others ?
- Among these entities, which one could be created by a class ? Which entities are in reality just data/attributes of a class ?
These questions are broad (and a bit complicated) and there is not just one solution !
Second step : explore the existing code The code above is achieving what we want to do in this exercise, but with the wrong paradigm, the procedural paradigm. We want to tranform it into an Oriented Object code
-
Have a look at the code above and try to think which piece of code you would be able to reuse. Do you find the data you've already spotted during the first step ? Which functions could be used as class methods ?
-
Write the name of the chosen functions in the notes you've made during the first part and bind them to a specific class.
Third step : Refactoring : write your own classes (This is HARD but a very good exercise if you feel confortable with concepts and the syntax)
- Refactor your code in order to get rid of all functions that are defined above the
if __name__ == '__main__'
. These functions will be put, in the end, in the new classes. In order to do it, you need to create several classes.Refactoring definition: "In computer programming and software design, code refactoring is the process of restructuring existing computer code [...] without changing its external behavior." Wikipedia
Fourth step : draw conclusions
- What are the benefits/the desavantages of a such refactoring ? Write at least four bullets.
Fifth step : finalize some functions
- To finish the challenge, you have to refactor the function formerly called
announce_challengers()
and to fill in the function formely calledinterview_challengers_podium()
.
5.Bonus Task: Extend the pet Clinic Example
- Write out all the code in the examples above in your preferred python environment and verify that they work for you
- Add the ability to specify an age of the pet to the
Pet
class - Create a list of 20 pets:
- 5 cats with different names and ages
- 5 dogs with different names and ages
- 5 turtles with different names and ages
- 5 birds with different names and ages
- Update the
hello
method in thePet
class to also print the age of the pet - Using a for-loop, go through the list of 20 pets and for each pet with an even-numbered age, make the pet say hello!
6. Bonus Task: Implement a REDI School Management System
- Create a
School
class which represents all the different REDI school locations - Each school location will be an object of the
School
class - Create a
Course
class which represents all the different courses offered at REDI School - Each actual course will be an object of the
Course
class - Create a
Student
class which represents all the different students in a REDI School course - Each actual student will be an object of the
Student
class - Each student object must have a name
- Each course object must have a course name and a list of students
- Each school object must have a location name and a list of courses
- Test your system by:
- Creating 3 REDI School objects representing the locatios in Germany
- Creating 1 course object representing a course offered at one of the schools (3 course objects in total)
- Creating students objects representing each of the students of the
Intro To CS
course.