[MUSIC] In this video, I'm going to talk about Inheritance. Inheritance is a mechanism by which you can have one class, inherit the behaviors of another class. This is a powerful technique that allows you to very easily build a group of different classes that have similar, but not identical, behaviors. [SOUND]. Did you hear that? What was that? Anyways, let's get started. Alright, so what is this Inheritance? I want to explain it by example, okay? So, let's imagine that I'm trying to build a chess game. And I decide to build a class of type chess piece. Okay. And, for simplicities sake let's just say that a chess piece has two methods. One, is color, which returns its color. And one is valid moves, which returns the moves that this piece can make. Alright, so, immediately she realized that color is easy to implement and it doesn't matter which piece I have, right. I can just initialize a piece to be white or black. And when I ask what its color is I get back white or black. Everything's fine, okay? Valid moves is obviously more complicated, because that depends on which chess piece this is. Alright, so, maybe your first reaction is that when you create a new chess piece you should pass in a string that says whether it's a knight or a rook or a pawn. And then valid moves is one big giant if, then, else, uuu, and you can return the valid moves that way. Well, that gets really ugly really fast. And while you can do it for chess pieces, for more complicated things, it starts to get, a little bit difficult to keep track of and to make work correctly. You're going to end up introducing a lot of bugs. Alright, so the correct thing to do here is to create what's called a sub-class. So, this is called, up here, a base class, because I'm going to base my other classes on this. And this is called a sub-class. Alright? And so we get a pawn. Now I don't need to have a color method for the pawn. I can just use the one up there in ChessPiece. Down here, I have to have a valid-moves method. And this just returns the moves that are valid for a pawn, okay? And in reality, you'd probably have more methods that are unique to the pawn, and maybe you'd have more methods up in the base class. Now when I want to have another, or build another type of chess piece, I go over here and I build a rook. And, I define valid moves for a rook. Okay, and I keep going and I define all the chess pieces, and so on. Now when I build my chess game, what I do is I just have a collection of chess pieces. I don't know which ones are which. I start out with the correct number, right? I start out with eight pawns and so on, okay? But I just put them on the board in their correct locations and from there on out, I play the game by simply asking the piece, what are your valid moves? And I check those valid moves if I can make them or not. And then I decide whether or not I'm going to let the player play. Or, if I have artificial intelligence, whether I'm going to make that play and so on. Okay. It comes down to, now. Instead of having a big if, [UNKNOWN], I just have a, I just call valid-moves on my piece, okay? So, I say, you know, basically, piece, equals pawn. And you know, maybe I initialize it by saying, black. Okay and then later when I want the valid moves I just say, piece dot valid moves. And you know, maybe I pass it aboard, and I get back the valid moves, okay? This will work no matter which subclass of chess piece, piece actually happens to be, because I will have implemented valid moves to do the right thing. Now, I have my chess pieces, and maybe I said you know, piece one is a pawn, and piece two is a rook, and piece three is a king, and so on. And maybe I put them in a big list, so I say pieces equals a list of p1, p2, dot-dot-dot. Okay. And now, the way I'm going to use this is as I said, right? I'm going to do things like pieces bracket 2 bracket dot color. Or pieces bracket 3 bracket dot valid moves. Okay, and hopefully this is a little bit more obvious that I have no idea, you know, what pieces bracket two, or pieces bracket three are, okay? They could be pawns, they could be rooks, they could be kings. I'm going to actually be able to get out what I want, alright? So, this is really what you're doing here. You're trying to you know, put them in variables, or, or places, or pass them to functions or so on, where you're just expecting a chess piece, and you don't know which chess piece you have. Now, you might recognize this from the previous video. I talked about building a queue and building a stack, right? And, they have exactly the same methods. And they have behaviors that are actually common. Like when you clear them, you do exactly the same thing. When you initialize them, you do exactly the same thing. And, this is a primary candidate for Inheritance, where I should've created a base class, called a restricted access container, and had queue in stack inherit from the base class. So why didn't we do that? Alright, well- >> Quack, quack. >> [LAUGH] What was that? Alright, so Python also does not actually pay attention to types very well, okay? So there's no way to enforce that I give you a RAC. And that's part of this whole thing, that If I give you, if I have a language that says, hey I will only accept a RAC as an argument, then you know you ended up with either a queue or a stack. Or if I could only put chess pieces into this list then I would know for sure that I always had a chess piece here. Python doesn't do this right? We've never actually had to tell Python what type anything is, anywhere. Okay, and one consequence of that is that Python does this thing called duck typing. >> [SOUND] Quack, quack. [SOUND] Quack, quack. [SOUND] Quack, quack. [SOUND] Quack. >> Alright, what the heck is duck typing? Well, if it looks like a duck, and it quacks like a duck, it must be a duck. Okay, so we can get away with not having this base class in Python. And the queue in the stack, each implement exactly the same methods. So, I can pass them both to any function. And that function doesn't need to know if it's a queue or a stack. It doesn't need to know that they should have been inheriting from the same thing. It just calls the methods. And, if they both have a push and a pop method, it'll call push and pop and everything will work just fine. Now, this is not the best way of doing things. Okay, it's better to have Inheritance. But, when, this, this does get used quite a bit in Python when you don't enforce the types, okay, you still have a problem, that you know, I can pass a queue, I can pass a stack. I could pass something completely different. Alright, let's look at a very simple example of Inheritance. I have two classes here. I call them base and sub. Alright, and you can see that I defined the base class to have two methods, hello and message. Okay. The subclass now has something that you've never seen before. Right? After I put the word sub I actually put in parentheses the word base saying that I want to inherit from a class named base. Okay, and now I defined a new method called message. So, I have, exactly the same name as the method in the base class. So, let's see what happens. If I create an object of type sub, alright. And I use exactly the same syntax, I don't put base inside there, right? Then I call that hello method and hmm. Sub doesn't have any help method called hello, so I wonder what's going to happen there. And then I called message and I send a message. So I wonder what's going to happen there. Well, let's try it. Okay, well, it does have a hello method. Because I inherited from base, I get everything from base that exists up there, okay? Now when I called message, you can see that it calls the message method down in the subclass. So if I redefine a method in the subclass, that overrides the methods up in the base class. And I want to point out that I could also make something of you know, base obj equals base. And I can call base obj dot hello. And I can call baseobj dot message. Another mess, if I could type correctly, another message. Alright and let's see what happens there. Okay when I do that, alright, it just prints another message without that sub prefix, so we know that I'm calling the message method of that base class, alright? And this is the basic idea behind Inheritance. Now there is a lot more to understand than this, but this gives you a simple feel for how to do it in Python. This is not the whole story. I want you think a little bit about how we're going to actually initialize objects when I'm using Inheritance, okay? So here's another simple example. I have a base class that doesn't do anything other than hold a number and allow you to print a string representation, or get a string representation of that number. And I have a subclass that does pretty much absolutely nothing. Okay? So, what I really want here is to pass the number 42. I want to create an object of the type, of the subclass type but I want to hold that 42 in self dot underbar number. Okay, up in the base class so that I can print it out. Right? So you might naively do the following. I'm just going to send 42 into the initializer and hope for the best. Okay, well let's run this. Alright, I get an error when I call the stir method from print down here, okay? It says I don't have anything called interbar number. Why? Well, Python does not automatically call the initializer of the base class, alright? It's your responsibility to do so. So I have an init method down here in the subclass, and I have a number so I want to pass that off to the base class. So you might think, alright, let's call self init, num. That seems right. Okay, I want to call init, I want to call this init up here. I could probably self dot under bar under bar stir under bar under bar and it would just work. It would call my base class. And let's see what happens here. Huh, well actually I get a recursion error, right? And we're going to learn about that in the future here. But, basically what's happening is I called myself. I didn't call the base class. I called myself. So I'm calling the innate method of the subclass. So, instead of doing that, let's actually put the base classes' name here, alright? So this is base dot init. So I'm saying I want to call this method up here. Let's try this. Hm, well that didn't work either. Why? Well because that method takes self and num. And usually that self magically gets put there because it was in front of the dot. But now I have the name of the class in front of the dot, not an object. So I'm not calling that method in the same way. So I actually have to pass self here. Alright, so, let's hope the [LAUGH] third time's the charm. Hey, it worked! Okay, so if you want to be able to actually initialize the base class, you're going to have to call that underbar underbar init underbar underbar method explicitly. And you can't just do that by using self dot init. I have to use the name of the base class. And underbar, underbar init, underbar, underbar. Okay, and then I have to pass self as the first argument because that's what that method is actually expecting, okay? Now, there are other ways of doing this in Python. Specifically there is a method, or a function called super that figures out what the base class is and helps you to do this. Alright? This is not currently implemented in CodeSculptor, and has to do with the fact that there are both new style and old style classes in Python. Alright. And, CodeSculptor implements it this way. You can also implement it the other way, which is what Python has moved in that direction, okay? And, concepts are still basically the same. I'm using the super function to basically call the initializer in the base class. So, there's nothing different about what's happening. I actually feel this way is a little bit more explicit about what you're actually doing. Okay, so that I think, sort of understanding wise this makes more sense. As you become you know, more comfortable with all this, then you know, perhaps the super way is a little bit easier. Now, in Python duck typing is pretty common. [LAUGH] And hopefully you're not going to forget it after this video. Those were my kids providing the quacking noises by the way. But even though you see duck typing in Python you can also use Inheritance. And Inheritance has some advantages. Basically you can group classes together to clearly indicate that they have something in common. And in other languages this is the only way that you can do things, that duck typing is not possible in all languages. Alright? So now you've seen Inheritance, and hopefully you understand that this is another way of doing things.