 Hey everybody, this is Brian. Welcome to the 11th Python tutorial. Today we're going to be discussing classes again with multiple heritants and constructors. So let's make a class and let's call it animal, which is going to inherit the object class, maybe. There we go. And we're going to say the animal has a name, so default for that is going to be not named. Now in some older versions of Python, I'm not sure if it applies to the newest, but this would be a static or a static variable which is shared through all instances of the class. That can get very dangerous. Depending on which specific version of Python, if you make two animals and you change the name on one, it would also change in the other one, possibly. Not all the time, but you'll see what I mean here in a minute. And we're going to also create a constructor. And you notice how I do double underscore? And we're going to do a knit self. This is called a constructor. A constructor is called every time an instance of the class is created. Remember a class is just a blueprint. You can make multiple animals from this class. The class itself is not an object. The class is just a blueprint for the object we're going to create. And when you don't include the constructor, a constructor is automatically created for you in memory, and it's called the default constructor, which literally looks like this. It's just def in itself pass, which means it does absolutely nothing. So why would you want to override? That's what happens when you make a function that already exists. You're overriding that function. Why would you want to override the initializer or the constructor? Well, in this case, it's because we want to actually do something when the class is created. So when an instance of this class is created, we want to do something. So let's say my animal equal animal. And let's run this. You can see how it called the constructor animal constructed. So you can put any sort of logic you want in here. Also on top of that, even without an instance of the animal class, we're just going to call the class directory or the blueprint directly. You can see we can access that variable. So we have this variable floating in memory, but we have no class or no object, I should say, that goes with that instance of that class. So that's why it's called a static variable. Now it's a little bit different. Some languages and some older versions of Python, I believe, when you changed it in one instance, it would change across all the instances, which is a bad thing. You don't want to do that. But in this case, it's static, meaning you don't even need an instance of the class in order to get it. So let's get rid of that. And let's make a couple classes here, because I want to really build upon what we've learned. We're going to call this reptile. And it's going to inherit the animal class. And let's say reptile has scales. And I'm just going to leave that static keyword there so you know it's static. And let's say reptile constructed. And we're just going to make a few of these, like we're going to make a mammal class, which inherits animal. Mammal has hair. And we're going to make another class. And let's call it class dragon, which inherits both the reptile class and the mammal class. Because, you know, a dragon will have hair and scales just because dragons are awesome. And we're going to say has wings equal true. Maybe if I can spell the word true. This, of course, is a static variable. And I'm just going to copy and paste this. That would be bad. Let's do that. There we go. Sometimes the Python indentation doesn't really work well with me. I'm not sure. I've spent most of my life in C++ and C sharp and other languages. All right. So let's actually flesh out this dragon class a little bit more. And we're going to work with the deconstructor. Maybe. There we go. My mouse was in the way. Deconstructor is called automatically when the class is deconstructed. So you have a constructor when it's made and a deconstructor when it's destroyed. We're going to say self class. And let's go get the class name here. That way we can see exactly what's going on. Let's say print. Oops. Yeah. Print print. That's good. Start. And we're going to print finished. And in between here we're going to actually do some work. So we're going to say my dragon because I've always wanted a dragon. Equal dragon. And we'll say my dragon name equal. Let's call my dragon Sam. Why not? Just because it's a dragon. Now when we run this you see how the program starts. Dragon constructed. Meaning we've made an instance of that dragon class. And we've set the name which you don't actually see anything for that. And then dragon destroyed after finished. What happens is it gets here. The Python interpreter sees that we are now done with this dragon object. And it calls the deconstructor and destroys it in memory. That's called automatic memory cleanup. Some languages also use what's called garbage collection. Meaning that object will actually stay in memory but you can't really access it. And then over time it will do garbage collection and clean up in the background. I believe it's also called pointer counting in some languages. Anyways I wanted you to be aware of static members. Remember you do not need it. An instance of the class in order to use a static member. So let's just play around here. Let's say dragon.name equal... Let's call it heather, my daughter's name. She's always wanted to be a dragon I guess. Print my dragon.name. Let's just see what happens if we do this. I'm not sure if it will change it or not. So now we've changed the name heather. Or we've changed the name to heather in all instances of that class. So let's actually make another instance here. Let's call it dragon one and two. So now we've got two instances. We've got the static member that we're going to change. And we're going to print dragon one and dragon two. And just kind of solidify this. I need a good dragon name. What's a good dragon name? Smog, why not? So we're setting dragon one to Sam. So we have dragon two to smog. And then we're saying the static name set to heather. What's going to happen when we run this? Well, it would help if I put the equal sign in there. There we go. You'll see now how it's calling Sam and Smog. It's printing it out instead of the default heather. What's happening there? We notice that if we don't set this right here, they're both heather. So let's set it for one and not the other. And then I'll explain what's going on. You can see one is Sam. We actually set it Sam. And one is heather. The one that's heather is dragon two. This guy that we commented out. Because we're setting this static variable, meaning that exists in all instances of that class. So why does dragon one still say Sam if we just set it? Because when you're calling that, it will now treat that variable as a class variable instead of a static variable or a member variable, if you will. So we're going to kind of wipe these out. I don't like wiping out dragons, but it's got to be done. Somebody's got to do it. All right, now we are going to actually modify mammal here. We're going to say self has backbone because mammals have backbones. Equal true. That's basically what it does. It'll take the variable name in this case and it'll say self dot dot dot, meaning it makes it specific to that class. Some older versions of Python don't do that. It would change it across all of them. So that's another gotcha. So now we have a static variable and a member variable inside of this class. If we try to take my dragon, and you can see it has all these things. It even has the has backbone. Let's try and print that out. Let's do this for a few things here. Let's do like hair or wings or something. Let's do hair. I'm not going to include the has in front. We know what we're talking about. So let's actually run this to see what happens. You can see how hair equals true. But suddenly we have an error. Backbone. Object has no attribute, has backbone. What doesn't make any sense, does it? I mean when we put the period here, IntelliSense says it exists. So we know we're inheriting it. But why don't we actually have access? There's no attribute. It's because we now need to initialize the classes we're inheriting from. And that goes with the concept called the super. It's a super class. And by super I don't mean that it's like Superman or it's super kind of like, you know, super spectacular. It just means that it's above it. What's it inheriting from? So we're going to say super. And we're going to say dragon because we need to know that we're currently passing the dragon class. Self. And it's self. And I'm going to put a little comment here. Must and it's the super. Let's run this again. Has no element backbone. Hmm. Let's do the magic of copy and paste here. Mouse is acting up. I think I need a mouse. I'm going to do it with animal, even though we could because it really doesn't have a super. It's super is object, which is pretty much already initialized anyways. Now everything runs and you can see backbone equals true. And that's because we've now initialized the supers. You got to go through the whole chain of what this thing's inheriting. And that's a good example of multiple inheritance with constructors. It can get kind of tricky here. What's happening now is you have a dragon class in memory, along with a reptile and a mammal. But they're superimposed if you will over this dragon. So now, dragon has a member named has backbone. You may be asking, well why don't you just put it right in the dragon class like this? And you can. But now you see the backbone is false, which is the opposite of the what we wanted with the mammal class. What you're doing there is you're shadowing. You're shadowing that variable. You're saying that the inherited variable no longer exists and you're going to use the one you've implicitly declared. I hate that word. Anyways, so just know that you have to initialize or call the constructor on your super classes in order to get their member variables. Well, we've actually covered a lot of ground here. One final thing I kind of want to cover is how to add variables in the constructors. So let's do this. Let's say we want to do we want to add an age in here. Self.age goes dragon's age, right? And we're going to set that to zero initially, but we're going to just say comma age. Now the first parameter in every constructor is the self object because it's creating an instance of it and you can get self. So while it's being called, Python is actually creating an instance of the class and handing it to you in the form of the self variable. You're now saying self.age, meaning you're adding a variable to the instance called age. And we're just going to say it's the age parameter. And we're going to say years old. Why not? You know, dragons do age. Let's run this. It says missing one requirement. Oh, it's because we never initialized it. And it's because it's a mandatory parameter. If we were to say zero equals zero I should say. Now we're setting the default value for that parameter and it would run like this and it would just say the dragon is constructed at zero years old and if we add, you know, dragon one's 100 years old. You'll see dragon, whoops, dragon is constructed and is 100 years old. Let's rewind that because I know it's probably a little bit confusing if this is your first language. What exactly is going on here? Well, we're calling the constructor. The self object is handed to us by the Python interpreter. It's an instance of the dragon class that we're currently in. Age is a parameter for the constructor. Some people call it default value. The default value is actually the equals zero right here. We're saying that it's an optional parameter. You don't actually have to include it. That's why this works. If you do not include it, it's going to equal the default value. In this case zero. We could say every dragon is automatically 50 years old and if we run it again you'll see the one that we did not give an age to is now 50 years old. We're saying self.age equal age. That's a bit confusing. What does that mean? What we're saying is self, meaning the current instance of this class, we're going to add a variable name age and it's going to equal the parameter of age. You notice how PyCharm automatically highlights it because it knows exactly where that's coming from. You could name this something else. You could call it just for illustrative purpose of dragon age. Why not? Then we'll name that there. Let's run that again. You can see it does the same thing. Just know that when that was named age, self.age and the age were two totally different variables. In that we're just simply printing it out. You can, of course, now access that. Print and let's say let's say %s is %d years old just because we want to do this, right? We'll say and really kind of solidify this concept here. We're going to name my dragon to smog. Why not? I think in the token books it's actually two g's but I'm just going to use one g. Let's run this. You'll see how Sam is now 100 years old. This is what we're printing out. What's really going on under the hood and we're going to wrap this conversation up because we had it short on time here is when we add the name parameter, when we modify the name variable it's no longer static. It is a member variable and we're setting the age through the constructor and we're just simply printing that back out. If you follow it along here we're setting the name which is all the way up in the animal class and we're setting the age which is all the way down in the dragon constructor. Questions, comments, concerns feel free to drop me a line or better yet join the Facebook void realms group. We've just broken over 200 members and it's usually faster to ask them and get like 20, 30 responses than to email me and wait six weeks for a hey, I don't know or did you try googling it? That's it. Hope you found this educational and entertaining and thank you for watching.