Class Inheritance
Overviewβ
This lesson assumes knowledge of classes and dives straight into the concept of inheritance. After a We Do to build a child class, there's an I Do that walks through overwriting the parent variables and methods.
Learning Objectivesβ
After this lesson, you will be able toβ¦
- Implement inheritance.
- Describe what has been inherited from one class to another.
- Overwrite variables and methods.
Durationβ
20 minutes
Agendaβ
| Duration | Activity |
|---|---|
| 3 mins | Welcome |
| 7 mins | Creating a Child Class |
| 8 mins | Overwriting Variables and Methods |
| 2 mins | Summary |
Discussion: Similar Classesβ
Phone is a class β there are hundreds of types of phones.
- What attributes and functions would a
Phonehave?
What about an iPhone? Or android_phone?
iPhoneandandroid_phonewould be objects of thePhoneclass.- But, there are different types of iPhones and Android phones.
- Should
IPhoneandAndroidPhonebe classes themselves?
What would you do?
- Brainstorm what a
Phoneclass would contain.
Talking Points: You could go further:
- You could say
IPhoneis a class β there are many types of iPhones.- What specific attributes would an
IPhonehave apart from other phones?
- What specific attributes would an
- You could say
AndroidPhoneis a class β there are many types of Android phones.- What specific attributes would an
AndroidPhonehave apart from other phones?"
- What specific attributes would an
AndroidPhoneandIPhoneare separate classes. However, they are both types ofPhone.
Introduction: Inheritanceβ
AndroidPhone and IPhone are separate classes and in the Phone class.
This is called inheritance: making classes that are subsets of other classes.
Phone is the parent class. It's a regular class! All phones:
- Have a phone number.
- Can place phone calls.
- Can send text messages.
IPhone is a child class. The child class inherits methods and properties from the parent class but can also define its own functionality. iPhones uniquely:
Have an
unlockmethod that accepts a fingerprint.Have a
set_fingerprintmethod that accepts a fingerprint.Mystery novels are a type of book, but there are tons of those. Sofas are a type of couch, which are a type of chair.
Talking Points:
- Inheritance allows us to extend functionality defined in a
parentclass (Phone) and createchildclasses (e.g.,IPhone,AndroidPhone) that extend and compartmentalize different pieces of functionality. - When we define a class to represent a
Phone, we can add the basic properties and functionality that all phones have.
We Do: Inheritanceβ
All phones have a phone number, can place phone calls, and can send text messages.
Start a new file, Phone.py. In it, let's start and test the class:
class Phone:
def __init__(self, phone_number):
self.number = phone_number
def call(self, other_number):
print("Calling from", self.number, "to", other_number)
def text(self, other_number, msg):
print("Sending text from", self.number, "to", other_number)
print(msg)
test_phone = Phone(5214)
test_phone.call(515)
test_phone.text(51121, "Hi!")
We Do: IPhone Classβ
Underneath the Phone class definition, let's create the IPhone class.
class IPhone(Phone):
# Class definitions accept a parameter specifying what class they inherit from.
def __init__(self, phone_number):
# super()` calls the `init` defined in the parent class.
super().__init__(phone_number)
# Now self.number is set, because that's what happens in the parent Phone _init_.
- When you get to super, scroll up to observe
Phone's super.
Talking Points:
- After we define
Phone, we can create classes that inherit from thePhoneclass and add their own properties and functionality. - Let's define two new classes that inherit from the
Phoneclass. - Notice how the
IPhoneclass doesn't repeat the code that attaches thephone_numberpassed to the__init__method to theselfreference. - The
IPhoneclass calls the parent constructor through the super method and allows the parent class to execute that default behavior.
We Do: IPhone Class IIβ
iPhones uniquely:
- Have an
unlockmethod that accepts a fingerprint. - Have a
set_fingerprintmethod that accepts a fingerprint.
class IPhone(Phone):
def __init__(self, phone_number):
super().__init__(phone_number)
# Under the call to super, we can define unique IPhone variables.
# Regular Phone objects won't have this!
self.fingerprint = None
# Here are methods unique to IPhone objects:
def set_fingerprint(self, fingerprint):
self.fingerprint = fingerprint
def unlock(self, fingerprint=None):
if fingerprint == self.fingerprint:
print("Phone unlocked. Fingerprint matches.")
else:
print("Phone locked. Fingerprint doesn't match.")
Side Discussion: Edge Casesβ
Look at:
def unlock(self, fingerprint=None):
if (fingerprint == self.fingerprint):
print("Phone unlocked. Fingerprint matches.")
else:
print("Phone locked. Fingerprint doesn't match.")
What if self.fingerprint is currently None? We need to account for this!
def unlock(self, fingerprint=None):
if (self.fingerprint == None):
print("Phone unlocked. No fingerprint needed.")
elif (fingerprint == self.fingerprint):
print("Phone unlocked. Fingerprint matches.")
else:
print("Phone locked. Fingerprint doesn't match.")
When programming, always watch for edge cases. This isn't specific to classes!
Teaching Tips:
- Be very clear that this isn't specific to classes β it's something to always watch out for, in functions,
forloops, and anything at all. Note that this is a reason why pseudocode is so important.
We Do: Testing IPhoneβ
Add some test lines at the bottom:
my_iphone = IPhone(151)
my_iphone.unlock()
my_iphone.set_fingerprint("Jory's Fingerprint")
my_iphone.unlock()
my_iphone.unlock("Jory's Fingerprint")
# And we can call the Phone methods:
my_iphone.call(515)
my_iphone.text(51121, "Hi!")
Try it! Then, try this. Why does it fail?
# Let's try a Phone object on an iPhone method.
test_phone.unlock()
Talking Points:
- We can create
IPhones,AndroidPhones, and still regularPhones.Phoneis being used as a parent class, but it's still a class! - Inheritance is an extremely powerful feature of classes.
- It allows us to create "generic" parent classes, such as the
Phone()class, and then create child classes likeIPhone()that represent subsets of the parent class. - We change the characteristics of the object when we define the
IPhone()class. - Because it inherits from
Phone(), we're still able to use the parent methodscall()andtext().- We don't need to rewrite these methods in the child class.
- Using inheritance, you can easily create hierarchies of functionality. This keeps your code clean and intuitive.
Quick Recap: Inheritanceβ
- A class can inherit from another class β a parent class and a child class.
- The child class can declare its own variables and methods, but it also has access to all the parents'.
## Parent class: A regular class ##
class Phone:
def __init__(self, phone_number):
self.number = phone_number
def call(self, other_number):
print("Calling from", self.number, "to", other_number)
test_phone = Phone(5214) # It's a regular class!
test_phone.call(515)
## Child class: Pass in the parent class and call super() ##
class IPhone(Phone):
def __init__(self, phone_number):
super().__init__(phone_number)
# Under the call to super, define unique child class variables and methods.
# Parent class objects won't have this!
self.fingerprint = None
def set_fingerprint(self, fingerprint):
self.fingerprint = fingerprint
my_iphone = IPhone(151) # Create an object as usual.
my_iphone.set_fingerprint("Jory's Fingerprint") # Call a method.
my_iphone.call(515) # Call a method from the parent class.
I Do: Overwriting Attributesβ
Next up: Overwriting attributes!
Let's switch to a new example. You don't need to follow along.
Here's a regular Building class:
class Building(object):
# Class variables
avg_sqft = 12_500
avg_bedrooms = 3
# No __init__ - there are no instance variables to declare!
# This is possible in any class, not just inheritance. (Building is a normal class.)
def describe_building(self):
print("Avg. Beds:", self.avg_bedrooms)
print("Avg. Sq. Ft.:", self.avg_sqft)
def get_avg_price(self):
price = self.avg_sqft * 5 + self.avg_bedrooms * 15_000
return price
my_building = Building()
my_building.describe_building()
- There's no
init! This is new. Note that this isn't unique to inheritance β right now, this is a regular class. - Observe the order of operations for the price math.
- This is a regular class, but walk through each line.
Talking Points:
- Here's a new class.
- In it, we have some attributes for the average square feet, bedrooms, and bathrooms of a building. We also have two functions: one to print the attributes out in
describe_building()and one to calculate the average price and return it based on those attributes inget_avg_price(). - Note: When we define our
Building()class and specifyBuilding(object)in the definition, we're indicating that theBuilding()class we're creating inherits characteristics from theobjectclass. - The built-in
objectclass in Python is the most basic "parent class" we could have.
I Do: Inheriting Buildingβ
Inheriting from Building, we can create a Mansion class.
# Call in the parent, Building, to the class definition.
class Mansion(Building):
pass
# Our child class definition goes here.
# Will have the same class variables, instance variables, and methods as Mansion objects.
Overwriting Variablesβ
What if we want the class variables to have different values? We can set new ones. Remember, child classes do not affect the parent class.
class Mansion(Building):
# Overwrite the class variables.
avg_sqft = 6
avg_bedrooms = 1
# We don't have a call to super __init__. Why?
# There's no __init__ in the parent to call!
### Now, let's try it out. ###
# This still has the old values.
my_building = Building()
my_building.describe_building()
# The mansion object has the new class variables!
avg_mansion = Mansion()
avg_mansion.describe_building()s
- Note that
Mansionis an entire class! Classes don't need to be fancy.
Talking Points:
- In this class definition, the average square feet, bedrooms, and bathrooms have been changed, but nothing else has been done.
- Because the
Mansion()class inherits from theBuilding()parent class, it has access to the class methods we defined forBuilding(). - It is important to note that child classes do not affect the functionality of the parent class. Below, we've added a function,
how_big(), to theMansion()class. - We don't have super because there's no
initin the parent!
Discussion: Child Class Methodsβ
In the Building class, we have:
def get_avg_price(self):
price = self.avg_sqft * 5 + self.avg_bedrooms * 15_000
return price
What if a Mansion's price calculation is different? What do you think we can do?
- overwriting class variables, we can overwrite methods.
Overwriting Methodsβ
We know that we can overwrite variables. Turns out, we can also overwrite methods!
class Mansion(Building):
def get_avg_price(self):
return 1_000_000
mans = Mansion()
bldg = Building()
bldg.get_avg_price()
# # returns `self.avg_sqft * 5 + self.avg_bedrooms * 15000`
mans.get_avg_price()
# Returns 1000000
Quick Reviewβ
When we make child classes, we can overwrite class variables and methods.
class Building(object):
# Class variables
avg_sqft = 12_500
avg_bedrooms = 3
def get_avg_price(self):
price = self.avg_sqft * 5 + self.avg_bedrooms * 15_000
return price
class Mansion(Building):
# Overwrite the class variables.
avg_sqft = 6
avg_bedrooms = 1
def get_avg_price(self):
return 1_000_000
Knowledge Checkβ
Consider the following classes:
class Building(object):
class Animal(object):
def is_mammal(self):
return True
def is_alive(self):
return True
class Grasshopper(Animal):
def is_small(self):
return True
You instantiate two objects: bug = Grasshopper() and cat = Animal(). Which of the following instance methods are available for each?
bug.is_mammal()bug.is_alive()bug.is_small()bug.is_animal()
Summary and Q&Aβ
Inheritance:
- Allows us to make classes using other classes as templates.
- Has a parent class (
Phone) and a child class (IPhone).- The parent class is still a usable class!
Child classes:
inheritmethods and properties from a parent class.- Have access to all of the functionality of its parent.
- Can have new attributes and methods.
- They won't be available to the parent.
- Can overwrite values from the parent class.