Barbara Liskov
MIT Computer Science Professor
first woman from U.S. to receive a Ph.D in computer science
Inheritance is useful when we need two kinds of things with similar behavior and a similar interface
We’ve seen an example of this with the Counter
class from the collections
module
Counter
inherits from dict
and does (almost all) the things a dict
does, plus some more
By default, a subclass inherits (reuses) all the methods of its parent class
A subclass can override methods of the parent class
An instance of a subclass is also an instance of the parent class
Barbara Liskov
MIT Computer Science Professor
first woman from U.S. to receive a Ph.D in computer science
If S is a subclass of C, then instances of C may be replaced with instances of S without breaking the program
Instances of a subclass should behave like instances of the parent class
Remember, instances of a subclass are also considered instances of the parent class
Parent class | Subclass |
|
|
type()
vs. isinstance()
type()
tells you what class an object belongs to
isinstance()
tells you whether an object is an instance of a particular class
Remember, instances of a subclass are also considered instances of the parent class
>>> s = SharingPerson("Siobhan")
>>> type(s) == Person
False
>>> isinstance(s, Person)
True
Sometimes we need a subclass to have a method whose inner workings are slightly different from those of the parent class
We can override the parent method by defining a method in the child class with the same name as the parent method
Parent class | Subclass |
|
|
It would be nice if we could define subclass methods in terms of parent methods
In other words, it would be nice if a subclass method could call the corresponding parent method
The problem is that by defining a method in the subclass with the same name as the method in the parent class, we can no longer use that name in the subclass to refer to the parent method
Consider this code:
class Greeter:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hi, I'm {self.name}!")
g = Greeter("Gretchen")
The usual way to use the greet()
method of g
is
g.greet()
But you can also do this:
Greeter.greet(g)
Most of the time, we should use the first approach above, not the second one. But when trying to call a method we are overriding, the first approach won’t work, but the second one will.
Parent class | Subclass |
|
|
super()
Calling the parent class works, but is kind of clunky
You have to know what the parent class is
You have to explicitly pass in a value for self
(not cool!)
If we decide later that we need to inherit from a different parent class, we would have to replace all our calls to the old parent class
super()
evaluates to "a proxy object that delegates method calls to a parent or sibling class"
So, super()
lets us call parent methods without calling the parent class directly and without having to specify a value for self
.
Parent class | Subclass |
|
|
Sometimes we need several classes to have the same interface even though they have important internal differences
We can write a parent class that has the method names we need, but where some of them don’t actually do anything useful
Then we can inherit from this class and flesh out the methods in the subclasses
Example: a tic tac toe game that can have human players or computer players
We can make an abstract Player
base class with concrete subclasses HumanPlayer
and ComputerPlayer
; then HumanPlayer
and ComputerPlayer
are considered instances of Player
Python classes can inherit (reuse) methods from a parent class
A subclass can override parent methods
super()
allows us to invoke a parent method within an overriden method
One way to make several related classes with a shared interface is to create an abstract base class and define the concrete classes as subclasses of the base class