KENDRA PUGH: Hi.
I'd like to talk to you today about inheritance as a
fundamental concept in object oriented programming, its use
in Python, and also tips and tricks for using inheritance
in Python and in the object oriented
programming paradigm in 6.01.
First thing I'm going to do is give a really quick crash
course on inheritance to catch you up to speed, and also so
that you're clear on what I mean when I say something like
parent class.
And also, I'm going to address the sort of nuances of using
inheritance while programming in an object
oriented fashion in Python.
A lot of the code in 6.01 uses the object oriented
programming paradigm.
And a lot of the code in 6.01 will
inherit from parent classes.
So this is part of the motivation for going through a
quick review, and then also indicating the most common
slip ups, and also the most significant things that you
may or may not have seen from other languages.
All right, first, a crash course on inheritance.
Let's look at the board.
Inheritance is the idea that you can arrange objects in a
hierarchical fashion such that very, very generalized or
basic things that are true of a whole group of objects can
be specified at a higher level.
And then, you can work your way down to progressively more
specific levels.
The most formal encounter you've probably had with this
thing, that approach, is the biological taxonomy, right?
Kingdom, phylum, class, order, family, genus, species.
Every species has all the properties of
that particular genus.
All the genuses of a particular family have the
properties of that family, and so on, and so forth.
That's a very concrete example.
But I find it a little boring.
So I'm going to talk about dog breeds instead.
You're probably familiar with the fact that golden
retrievers are a type of retrievers and that retrievers
are a particular kind of dog.
You can make generalizations about goldens based on what
you know about dogs, right?
All dogs bark.
All dogs have four legs if they aren't injured or have
some sort of congenital defect, that kind of thing.
And goldens also have all the properties
of retrievers, right?
They are capable of going and catching game that you've
either shot, or possibly chase it down and
bring it back to you.
So they're bred to have very particular properties.
Goldens are also bred to have very particular properties.
And those that are very specific to goldens define the
difference between a golden versus a retriever in the
general sense.
Likewise, when we want to make objects that have very
particular properties but also share general properties with
other objects, we're going to create a new category of
object and put the specifics in that very specific category
and then take the things that we can generalize and put them
in more general categories so we don't end up rewriting a
lot of code.
Or we end up reusing code, but not copying and pasting it
everywhere because that's annoying.
The other major advantage of using inheritance is that code
is more intuitive.
You can make references to the same piece of code
all over the place.
But it's not as intuitively accessible to do that over,
and over, and over again, right?
It's really convenient to think of the fact that golden
could be a subclass or subtype of retriever, and that
retriever could be a subclass or subtype of dog.
When I talk about this relationship in terms of
object oriented programming--
when I talk about these categories in terms of object
oriented programming and when you're actually looking at
code, goldens are a subclass, or child class, of retrievers.
And retrievers are a parent class or
super class of goldens.
Likewise, dogs are a parent class of retrievers.
So now, I've defined my terminology and also hopefully
given you a very, very, very quick review of inheritance.
Now, I'm going to talk about the specifics in Python.
If I turn over here, I've written up a very short class
definition for dog, right?
Every dog has the class attribute, cry.
Every dog has an initialization method that
gives every dog a very specific name that is passed
in when you initialize the dog.
And every dog has access to the class method, greeting,
which returns a string that says, "I'm," whatever the name
of the dog is, and also the specific cry, which in this
case, is actually the class cry.
If you're unfamiliar with using the plus in terms of
strings, it's just a concatenator.
So play around with that in IDLE if you're confused.
I would recommend copying all of this into IDLE, and then
playing around with a particular instantiation of
dogs, in this case, Lassie.
If you look at Lassie.name, you'll end up going after
self.name, which is specified when your
initialize the object.
So Lassie's name is Lassie.
Likewise, if you were to type in Lassie.greeting, open
paren, close paren, and hit Enter, you should get a string
return that says, "I'm Lassie," comma, "bark." Mostly
this is to familiarize you with object oriented in Python
in the general sense.
Now, we're going to look at what happens when you want to
set up a subclass.
If I set up class Retriever and I want to inherit from the
super-class, Dog, I'm going to pass in Dog.
This is in the same syntax that I would use if it were a
function and I wanted to pass in a parameter.
If I wanted to inherit from multiple things or multiple
classes, I would put multiple classes here.
Right now, we're just going to inherit from Dog.
Note that I have no code here.
This is pretty much meant to explicitly specify the fact
that Retriever is not actually going to introduce any new
properties to dogs.
Their types are going to be different.
So if I create something that's a Retriever, it will be
of object type Retriever, versus if I create something
and say, "Dog," open paren, close paren, it's going to be
of type Dog.
But what happens when I create a Retriever--
and as an aside, if you know who Benji is, I know he's not
a retriever.
But bear with me here.
If I create a Retriever, it's first going to look for an
initialization in any other methods or attributes in the
Retriever class definition, run any code that's here, and
then go to the parent class, and run all the code here.
So even though Retriever did not have any explicit code
underneath it, I can still interact with the object,
Benji, the same way that I interacted
with the object Lassie.
It has all the same methods and all the same attributes.
Phew.
So there's basic inheritance.
And I will make another aside that if you're doing this, you
probably don't need to create a subclass in the first place.
If you're designing your own code, and you're trying to
think about what the best way to organize things is, if you
have to create a subtype or a subclass and there are no new
methods or attributes or no different ways of addressing
those methods or attributes, then this category is probably
actually just this category.
You may want to make a difference so that you can do
interesting things with type checking.
I think that's the only thing I can think of that would
justify it.
And I might be wrong.
Python gurus out there should correct me.
But a thing to keep in mind.
So we've done the first half of our inheritance.
We're going to inherit one more time and create a class
of golden retrievers.
Once again, I've got my class definition and my indication
that I'm going to inherit from Retriever.
I don't have any initialization or attribute
assignments.
I only have a definition for greeting.
So what happens here?
Well, the first thing we always do is look for an
initialization method.
Golden doesn't have one, so it's going to check the
Retriever class.
Retriever doesn't have one, so it's going to
check the Dog class.
The initialization method is here.
So when it runs the initialization method, it's
going to run this code.
The first thing that's going to happen is any code, or any
attribute assignments, or method definitions here are
going to be considered the canon, or the first thing that
any Golden is going to reference.
So greeting is going to be executed before greeting used
in any other place.
You notice the only difference between this greeting and the
Dog greeting is that "OHAI!" has been
prepended to the phrase.
And the way that we end up doing that is we refer to-- we
concatenate, and then refer to the superclass.
And once again, we have to pass in the explicit argument,
self, when we're talking about a class definition.
Later, when you actually instantiate an object and use
your parens, you're not going to have to
put self as an argument.
It'll get confused.
We'll go over that in a second.
So let's say I create a golden retriever, Sidney.
I'm going to pass in one argument, which is the name.
We're going to consider all the definitions here first,
which means that goldens are going to have a method for
greeting that is specified here.
It's going to use the method for greeting from Retriever.
And we could put in anything here, right?
We could put Dog.greeting.
We could put in some other function that is in the same
environment as class Golden.
But here, we can explicitly access the superclass that we
defined here.
We're going to head over to Retriever to see if there any
additional methods or attributes that are a
consequence of being a subclass of Retriever that we
need to add to our definition.
Now, we just hit the pass.
On the other hand, Retriever inherits from Dog.
So once again, we have to jump over to a super-class and grab
any attributes or methods that are defined there as well.
So all the way back over to Sidney.
When I call Sidney.greeting(), the first thing that happens
is that I look in the most specific subclass, or whatever
my object type is and see if there's a
definition for the method.
Because there is, I'm not going to use Dog.greeting().
I'm going to use Golden.greeting().
Golden.greeting() says return a string that says, "OHAI!"
And also append it to whatever Retriever.greeting() returns.
I go over to Retriever.
It's not here, but I still have a reference to Dog.
I go over to Dog.
It has a method for greeting.
And it says, "I'm Sidney.
Bark." So the final return type should be, "OHAI.
I'm Sidney.
Bark."
This concludes my basic overview of inheritance of
object-oriented programming in Python for 6.01.
Next time, I'll review some interesting features in Python
that actually originated in earlier languages and also
particularly things in aliasing that people that are
new to Python or people that are new to programming find
especially confusing.