12/April - Object-oriented Python

python gif

Prerequisites


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.

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.

Jigsaw

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
Note: The 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>
Note: The 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
Note: The self parameter is a reference to the current class object and is used to access variables that belong to the object.

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

Understanding the concept of class can be a bit difficult at first. This section is not essential if you are still struggling with the previous concepts. ;)

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 the Cat class which causes the cat to make the meow sound
  • A bark method to the Dog class which causes the cat to bark
  • A fly method to the Bird class which causes the bird to fly
  • A hide method to the Turtle 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 !

SOLUTION : You can check this document to see which classes could be interesting to create (slide 1). Don't hesitate to let comments on the doc if you have questions.

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.

If you need help you can check this document. From slide 3 to 6, you will find the attributes that you have to put in the class. From slide 7 to 21, you will find the methods that you have to implement in your classes.
If you have finish these two steps, it's time now to write python code. Make sure that you know well the syntax of python classes, don't hesitate to read again the part 4 of the lecture and do the pet example by yourself.

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 called interview_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 the Pet 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.

Additional Resources