Inheritance
Inheritance allows you to reuse code by creating a hierarchy of classes. Let's say that you wanted to create two classes, one for baseball teams and one for football teams. There are going to be some attributes that are common between those classes.
To save code, you might want to create a parent class that's for sports teams in general. It might have things that are common between baseball and football teams.
class Sports:
def __init__(self, name, city):
self.name = name
self.city = city
def go_team(self):
print("""Let's go {} from the great city of {}.""".format(
self.name,
self.city))
You can then pass Sports
as an argument to new classes for both Baseball and Football and it will inherit its attributes and methods:
class Baseball(Sports):
def homerun(self):
print("We hit a homerun!")
class Football(Sports):
def touchdown(self):
print("We scored a touchdown!")
Try out using the go_team()
method from the Sports
class after initializing an object using the Baseball
class:
redsox = Baseball("Redsox", "Boston")
redsox.go_team()
Using super()
You can access the parent's class's method directly in the child's class by using super()
. We are going to run away from our sports
and baseball
example to get a better hold of this.
Imagine that you have a parent class for rectangles and child class for squares (since a square is just a special type of rectangle):
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
class Square:
def __init__(self, length_sq):
self.length_sq = length_sq
def area(self):
return self.length_sq * self.length_sq
The area()
methods are very similar for both of these, and we could simplify this with super()
.
If only we could just barely change the __init__
so instead of taking length
and width
, it would pass the length_sq
into the constructor of its parent's class.
class Rectangle:
def __init__(self, length, width):
self.length = length
self.width = width
def area(self):
return self.length * self.width
class Square(Rectangle):
def __init__(self, length_sq):
super().__init__(length_sq, length_sq)
That way when initializing the object, you just need to pass one variable into the Square()
class.
sq = Square(2)
sq.area()
To be extra clear, here is what happens:
- The "2" from
Square(2)
is passed into the constructor ofSquare
class:
class Square(Rectangle):
def __init__(self, 2):
super().__init__(length_sq, length_sq)
- It is then passed into the
super()
method as its arguments:
class Square(Rectangle):
def __init__(self, length_sq):
super().__init__(2, 2)
- Which then in turn passes the "2" to the constructor of the parent class:
class Rectangle:
def __init__(self, 2, 2):
self.length = length
self.width = width
Multiple Inheritance
What if you want a child class to inherit from two different parent classes? I actually think that this can be pretty challenging, but as it so often does, stackoverlow comes to the rescue.
First, let's create a Television
class:
class Television:
def __init__(self, channel):
self.channel = channel
def watch_tv(self):
print("Its on " + self.channel)
A baseball class might want to inherit properties from both Television
and Sports
. The constructor in our new baseball class will become a bit more complicated.
Without Super
We are going to explicitly call the constructors from our parent classes and then pass in their arguments into them:
class Baseball(Sports, Television):
def __init__(self, name, city, channel):
Sports.__init__(self, name, city) # explicit calls without super
Television.__init__(self, channel)
def homerun(self):
print("We hit a homerun!")
Let check and make sure that it worked:
redsox = Baseball("redsox", "boston", "espn")
# from the baseball class
redsox.homerun()
# from the sports parent class
redsox.go_team()
# from the television class
redsox.watch_tv()
With Super
With super, it is a little more complicated. The first super calls the first parent class, and then we have to explicitly tell it to find everything past the first parent class.
class Baseball(Sports, Television):
def __init__(self, name, city, channel):
super().__init__(name, city) # calls the constructor of Sports
super(Sports, self).__init__(channel) # constructors after Sports
def homerun(self):
print("We hit a homerun!")