 Okay, we're now live on YouTube. Sorry for the technical difficulties. I will try and fix that later, but welcome back to the final unit review for Python introduction to Python sailors CS 105. I've now hear myself on things. Sorry, everyone. But so I'll make sure there are links to everything in the chat for you guys but before without further ado let's hand it over to Dr. Sack to take it away. Well, hi everybody. If you're here, it means that you have made it to unit 10. So you can pat yourself on the back and, you know, thank you for your diligence so just going to try and review, you know, some concepts and ideas from object oriented programming. This is really meant to, you know, just to be an introduction that kind of scratch the surface, you know, to get some of the basic terminology down because it's, you know, object oriented. I think programming is, it's a fairly deep subject. But it's, it's not hard to understand, you know, why there would be a paradigm shift in in programming from, let's say the initial roots of what was called procedural programming which is which is pretty much for the most part what we've been doing into the realm of object oriented program which is really important I think for for applications because usually when you're designing large scale applications, you know, you know, developing, you know, an Adobe platform or something like that or an operating system or something that requires you to really, really think about things ahead of time to really sit down and design, you know, from sort of a top level down to a lower level. You know, what are the most important aspects of this, you know, grand piece of software that you're designing what do you have to do to make sure that that there's a, you know, seamless implementation and and and when you go into that software 10 years later to have to you know, have some type of revision, you know, is it is it is it a seamless process to be able to do that or do you have to go into a million lines of code and, you know, go into a rats nest of code and and so, so when you're doing object oriented program you, you know, you're really thinking about sort of large scale applications and and and you're sort of, you're really able to sit and categorize. You know, you're thinking basically you have to be a very organized designer, and because, you know, if you, if you start to maybe designing application around a house well inside the house there are rooms, and then inside the rooms depending on the room there are locations if you're in the kitchen well then you're, you know, dealing with cooking in the storage of food, which is different from a bedroom, because then you would have a dress or a furniture inside of a bedroom where you would have drawers that would contain clothing and the clothing, you know, unless you're, you know, a freshman college student, you know, you, you, you have different drawers that have different clothing and maybe you have like a sock drawer and a, and a pants drawer and a shirt drawer or something like that. So, so that's the kind of, you know, sort of top down, you know, kind of abstraction that you're thinking about when you are object oriented programming. And you're, and you're trying to define classes of information basically and and then when you design a class, you think, well, if I have this class, you know, what kind of functions do I want to implement within that class and what kind of data do I need to make that that specific class work. And so, you know, usually, you know, like I said, when you start to see full loan applications you see many class definitions are inside of those class definitions of functions that are relevant and and also and also data as well So, so that that's the way that we're thinking, you know, and again, that's different from and the course goes into this it goes it's different than procedural programming where in procedural programming, you know, you have some type of a goal, and then you work through procedures to have some type of a calculation basically, you know, you call functions and then and you know you're done because you've reached the other side of that procedure, you know, through a series of function calls and, and so the, the arrangement, you know, first of all, and the programming philosophy is quite different than than what it would be for object oriented programming. So that the key thing I, you know, I felt like to get to at the introductory level as as I would in any programming course regardless of the language, you know, is to begin to introduce students to the concept of a cleanse. So usually, you know, you come up with really basic, you know, mundane kind of examples because the classes class definitions can grow quite large very quickly. And it becomes difficult to, to help students kind of get the thread of the class when you haven't start those six, seven different methods and, you know, so usually that the introductory examples are very small, and very handleable and understandable so we take an example like oh let's make believe I want to characterize the time like you think of a digital clock or something like that. So the type of data attributes the data that would be associated with time might be hours minutes and seconds it might be days it might be well you know in a hurry milliseconds you know something like that. And then of course you have to think about the types of operations or functions you would want to operate on those data attributes. And we call those methods so so basically a function, you know in the vernacular the function within a class definition is a method basically and you know that already I mean you know we've, we've, you know, I'll show this you know if you've had a taste of, you know, of method calls already because we've had to use them to handle objects built in objects within Python so so there'll be no real surprises I think with regard to to syntax today. But so so different kinds of methods for, let's say, handling time might be if you're going to set a digital clock you might want to set the time or you might want to get the time, or you might have an alarm that you might want to set or you might want to reset the alarm those are different functions that you would want to perform so those are those are typical kinds of methods you might you might integrate into a time class let's say. So class definitions in general they they they contain data attributes and methods that and here's the key point is that they are relevant to the class definition. Okay, they're relevant to the class definition so when you have a class definition as I said before you're you're kind of thinking through writing the program long before you actually, you know, you're sort of map things out well ahead of time before you actually find start to program anything because that's that's you know kind of how you would solve problems and kind of really have to organize your thinking well in advance of what the final product is going to be. And again so for method syntax you should be very clear on this because you've seen the dot notation and the method syntax is is really similar to the function syntax module that dot notation. And then so and also the concept of an object you know once once you have a class. Now what you can do is with respect to that class you can define instances of that class that can operate on that can operate on data, you know attributes using class methods and so forth. So the instance of a class is is the object, and the object is what you and is what you, you know, use to make computations with you know the class definition is the definition the objects are what you are what you, you know, sort of program with. And again just a simple example I think this is probably really quickly illustrates that, again, as I've said probably throughout the course is is that is because this is just the way you'll think is that, you know, I'm going to put everything in Python is an object. And when you have an object that means that you have, you know, access to all the methods that we'd be associated with that, the class definition from which that object came. Okay, so make leave in Python is just forming a list you know you're all experts that list. So, so the class the class is list. Okay, the class definition has to do with this this concept of a list well what's a list, you know a list is in an ordered collection of objects. So it's kind of like uses the definition with a definition but but you get the point is that is that as long as you can have this ordered collection of objects in this case they're just numbers they're just this is a numerical list. It's the sake of brevity but you can check anything into a list, and it can be an and it can be an object as well. But a is an object instantiated it's an instance, it's instantiated from the class list. So if you recognize that then then you have access to all the methods that that you know you could use to operate on a list with one of which we have immense amount of experience with is the append method which is used to append data to, which is used to to a list, and that's the syntax for doing so so the method call is like a function call append, you know left parentheses right parentheses means the input values 24. And then of course the dot notation connects basically the method to the object that you've instantiated. The append if it be world list or see or see that a pen means that that see has its own data has its own data attributes it, you know, a b and c are different, you know, but, but, but the append method is is used for, you know, part and parcel with all the, with all those with all those different objects. You know, you could think of an object is kind of like a suitcase that contains the data attributes and all the methods that's a bit of a fit because really, it has all the attributes but the methods really aren't in the suitcase because that would be too much to carry around. But you can think of it that way conceptually is that is that every object has it has its own data, and then has access to the methods associated with the class and so. So that's some experience measure experience with built in classes already. Now the question is, how do we extend that to be able to create user defined classes which is really the, that's what you want in a programming language right it's like it's like if you are confined to the set of classes that are that are built in, you know, or the set of functions or the set of whatever that are built in to the language to get the language up and running. It's really not a very good language what you want to be able to do as as a program as a creator, basically, is that you want to be able to create your own classes. And what you get to do really I mean think about this now you get just like functions you know with functions you get to create a never before existing instruction, a Python instruction that's what a function is it doesn't exist in the Python language you created same thing with classes you get to define your own classes. And now you've created your own brand new variable type basically you, you get to create your variable types, and you get to define what methods can operate on that variable type and you get to define what data is contained in that variable type so it's, you know, that that's really what you want to be able to do as a program is recognize that you have the freedom to do pretty much anything that you want to do, you know, to solve any problem if anything can be computed, you know, you have to have the tools at your fingertips to be able to compute what you want to compute. So, so today's today's lesson is not so much about built in classes because you know most of them already you know about dictionaries, you know about sets list tuples and on and on and on. So, so, in this case, we want to grow a little bit more get stretched a little bit more into into defining our own, our own classes. So, maybe we'll come over to our friend. We'll do something like this and see what I have here. Okay. So, um, yeah, we'll start here. So let's talk about the syntax for designing. Assuming I'm sharing with me don't check this, the syntax for designing classes. Yeah. And so the first thing is just what's the syntax what's the syntax for the class definition well no surprise. There's a special keyword called class. And what I'm going to do again with these initial examples they're very boring examples but but they're meant to be small, because you know, rather than you know, chuck the whole kitchen sink at you at once you know we just start with it. So I'm going to define a class called a rectangle. What's interesting about a rectangle a rectangle has a height and a width. Okay. And so that's all there is to it. It's it's simple. It's simple to understand to get across the point of all the syntax that will go into constructing a Python class and and the beauty of this is that a lot of this what I'm going to tell you in some sense. Not all of it like I said some becomes very language dependent, but a lot of the concepts you can take into other languages. You know for that, you know, you might want to, you know, you would want to do some form of object oriented programming. And again, it's just the concepts are transferable to any language in some sense, whereas this, you know the syntax will be different. The syntax is the it's the class is the key where the name of the classes rectangle and lonely holders a colon, after the name of the class. And so that's very consistent once again with everything that we've done so far. And it's rightfully so because because you know you don't want to have to know when learning syntax you don't have to remember 100 different things. I mean you can like I said some languages are like that but there should be some measure of consistency so that this says I'm this tells Python I'm starting my own user defined class. Okay, and again so so the next thing is that it's going to contain various attributes. And so again we've already agreed that a rectangle should have a height and a width. Okay, so so what I decided to do is call the attributes the data attributes within my class height and width. And the key is that is that it's, it's, it's not just that there's a height and a width there's a height and a width defined. The expectation is that we're going to be instantiating instantiating an object that is going to require the use of the height and width to operate as you can see here maybe to define the area of a rectangle which is the width times the height or the perimeter. You know around a rectangle is going to be you know two times the width plus two that's the that's the distance around. So it's the height plus the width plus the height plus the where you know or two times the width plus two times the height so again very, you know, uninteresting calculations and then you'll know how to compute the area in the perimeter. I wanted to throw another one in here for just to keep things interesting so they would be an input argument. Maybe you want to take the, maybe you want to take the rectangle and take its height and its width and scale it by some factor, you know, and multiply it by something from scale factors so this method would go ahead and and and multiply the width and the height by the scale factor. And so, what's this thing about about self I'll come back to that in a second. Probably, you know, the closest thing that you could relate it to, if you see in maybe other languages is this, you know, like in C++ there's the this pointer. So, the cell will come back to in a moment I just want to talk about the notion of object instantiation the expectation is when you're going to instantiate an object from the class. Something has to happen every language has its rules for something happening when you instantiate an object. And oftentimes there's this notion of what's called a constructor. And, you know, there's a, there is the concept of a constructor is that the constructor knows what to do in some sense, when you go ahead and actually create an object from a certain cleanse. And if, if, if you don't define the constructor, then the language will make decisions for you in some sense, this will be something because, because once the object is instantiated it has to occupy some someplace in memory. It's got to be sitting there it's got to be physically available and and and depending on depending on how the constructor runs basically that's going to define. Not what that object looks like in memory if I could put it that way we haven't gone into too much, you know, at the low level but I'm merely stating that that when when you when you instantiate an object. A lot of stuff happens and and you know we don't have time at the introductory level to go into all of that but but if you want to, let's say control what happens then then you have to control the instantiation of the object you want something to happen. You have to make that happen you have to do that. So one way to do that one avenue one vehicle for for doing that is this emit method, and this is where we're starting to get down to the nitty gritty of of the Python language for object instantiation. Okay, the object instantiation, let's assume that when you create the object, you want to define the values for the height and the width. So have the height and the width as inputs to our method, which I'm calling a knit. And I'm going to have these data attributes contained within the class called height and width. Now, they're not just heightened with variables it can't be like that because the class is just the definition. The application is your planning on instantiation object that's going to have a type rectangle of data type rectangle that's going to have a height and width. So I could define one rank rectangle with without what one height and width and another rectangle with another height and another rectangle and I can just on and on create so many different objects. So each object is it's going to have its own height and width. Okay. So, so how does that happen well that's where the self comes in. Okay, that's where the self comes in the self is saying basically, it's me, I'm the object right now whatever object is being instantiated I'm the object. And I know that that if I am this object I have this, you know this height equal to three and that and that with equal to five. And that object remembers those values. Okay, but the way that those values get set so that the object knows what its height and width are that specific object. It's got to be done intentionally. One way to do this and a very common way to do it and I don't want to say exclusively though but this is this is introductory. You know, the, the way of of instantiating objects is is really at your disposal, you know, you, if you are the expert, you know, you have a reason for why you're instantiating the object and you have a reason for how you're building that object. So, you know, there's a lot to making what are called constructors. And it's a deep subject and one that like I said it isn't really that necessarily going to it at the introductory level, but minimally the init method can act like a can or can can play the role of the part of a constructor that sets the data attributes, let's put it that way so part of what you want to construct your to do is to set the data attributes, because once the data is known, then that object knows what its data is basically. Okay, so, so this is how you do it. Now this is the init I'm going to come back to this in a little while but these little double underscores this to underscores at the beginning, and there's two underscores at the end. The double underscore method, or for short a Dunder method, sometimes the word term magic method is used. It's a very, very important method, because because the double underscore methods are magic methods. They run without you calling them you don't have to explicitly call the init method to set the data attributes. Okay, as part of the constructor you don't have to do that. I'm going to come back before you automatically. And I'm going to come back to magic methods in a few minutes but I just want to say for this, you're never going to have something that looks like object dot init that's not going to happen. What's going to happen is is you're going to instantiate an object. And then because because of the sheer fact that you instantiate the object, the init function runs automatically so you never call the init method. And here, just with that start just with that introduction, we've got the classroom we'll get to all this other stuff in a second. Okay, really want to focus on on what's going on is very a lot of stuff to point out. But so for the class rectangle, let's make believe we've put this method, the init method in there and the syntax is, you know, I'm referring to myself, I'm the object in question, and then I'm going to set these attributes, the height and the width equal to these input values. So let's go down to the code and name. This would be an example of an object extantiation. What's what we're saying here is that is that I'm going to define a rectangle. I'm going to call it R one so R one is the object. Okay, R one is being set equal to rectangle, and I'm calling rectangle with the parameters height and width equal to two comma four, or within height I forget the word that I didn't just double check with and height I'm sorry. So, so the first argument is x. So that's what I called the width, and then why is, you know, on Tuesday, I'll reverse these so so right now, we've got the width equal to x and the height equal to y, and those are the input so it's within height. So the syntax for in instantiating an object based upon my user definition. Okay, based upon my user defined plans is rectangle with a two height equal for, or for the second rectangle and object I'm going to define R two with one and height equal to three and notice. It's very, very important. Okay, because, again, different languages they work, they work differently. Okay, so in Python notice this when I when I instantiate the object and I invoke the statement rectangle two comma four. What happens is because the init method is contained within my class definition, the init method will run automatically, and there will be an object instantiated or created or it will get an instance of that class that will contain the values two and four for the width and height. There will be another rectangle object instantiated I'm calling R two, and, and it will have a width of one and a height equal to three. Now notice the difference very important. Okay, really important, because this is probably the, you know, when we exercise your own user defined function calls for instance or even with this this unless you haven't really talked about class definitions. But if you go back to everything that you learned about functions, pretty much there was a one to one correspondence between the function call and the function definition and the function call. If you have five input arguments, then your expectation is within the function definition, there will be five input arguments that will be contained as part of part of as part of that function definition. Okay, in this case, watch in slow motion very important with these parameters and the object instantiation of rectangle and the init method is running. But look at the init method, the init method doesn't have two parameters for the width and the height. It has one more it has three. So this is so self is not a Python keyword so much as it is an agreed upon convention that if we're using the word self. That means that as the as the first argument to the init method. Okay, or to a method within the clans, then the input parameters follow after sell. Okay, so if you need to use self if you're planning on accessing the attributes that are internal to that object. Okay, that that notice there are three input parameters, whereas the object instantiation only has two parameters. Okay. And this is like I said this is a big deal to point out it's syntactical, but you need to know it like if you do this without the self if you were to do something like this, just like you would do a method call I mean a function call. When you would do a function call your expectation is that two parameters in there for the function definition has to have two parameters, not so for for method calls. Like the method call is going to make reference to attributes within itself. Okay, that object is referencing attributes within itself, then you have to include that cell, you know convention basically. That's that's how let's say that's the important part about the init is that is that these two double underscores indicate that this is going to be a method that's going to run automatically in response to the instantiation of the object. Okay, it's very, very important is that you don't call it, it runs by itself. And, and again that's why some people kick around the term constructor for the init method is because you're trying to draw analogies to other languages maybe that one is programmed in, and, and there's this notion of running a constructor, you know based upon some other other syntax, and there are similarities they they are. There are similarities. So, so that's enough said about that so this is how you initialize the rectangle basically now. Once the data is there, then you might want to go ahead and compute for instance the area, you know, or the, or the perimeter of the rectangle again very mundane calculation but I'm just, you got to come up with small examples to get something to get the point I will also say something as well right now about getter and setter methods, because a common way, you know you're interested in accessing the data attributes would be simply to, you know return the value in an organized fashion to say oh go ahead and get me the width. Notice here, the cell, just again, here's self once again because because the object is making reference to itself, where to get the height, making reference to ourselves, maybe we want to set the width. So you have a method that sets the width sets that data attribute to an input value x, or sets the width. I'm sorry it sets the height to an input value for the height. Okay. And so, so in this case when we go ahead and run this if we run this code. Okay, we see that the object instantiation is our one or two with these different values and so you can go ahead and get these values from this function you can read them out. If you wanted to, if you wanted to do it this way. You could, you could do this I. It's always hard, you know creating this this introductory level because I think when I was doing this my expectation was that you know there might be like it like an object oriented version of Python kind of a course, you know that would take these concepts and be able to really unravel them more deeply. So, so it's like in constructing this it's like I was kind of navigating through, you know, trying to avoid a certain topics that that will require even more unraveling. I'm showing you these. I'm showing you these methods because they are, they are techniques for reading values contained within an object, but there are concepts, you know that that deal with basically privileges of whether or not you have the right actually to read those data attributes or are you even allowed to do so. And again different languages, you know have different defaults, you know, a C++ for instance would, you know, would it handles the construction of data attributes differently in some sense then maybe like a Python or something like that and Python. It turns out that that you need to know for instance that these concepts of public versus private versus protected data and what privileges you have. And I'll just, I'll just say because, again, this would just open up a whole can of worms, but, but data attributes and Python are by default public, whether you like it or not you know like I said that's going to rub some that's corrupt some object oriented in the wrong way because they'll be like oh well they should default to private you know this type of thing, I just didn't want to open up that can of worms I just feel like that discussion is probably more, you know, towards a towards a like in a more an advanced level of programming where we really get underneath the hood for object oriented programming. All I'm trying to do here is at least introduce the idea that there are very structured ways of accessing data attributes for which you can construct some type of a get function. If I could put it that way to go ahead and get that data. And, and I'll leave it at that. Okay, because like I said this this this would just open up another discussion that, you know, we could we could spend another, you know, our talking about. So I'll leave it at that. And then of course, you know you can also set values as well. So, maybe that's something over here and we just see. You know you might want to go ahead and do something like this let's let's go ahead and, and let's see the the methods are there. So again, so here's a perfect example of let's say if you want to set the values contained within the object or to maybe I want to set the width to five and the and the height equal to four. So once I've set them, you know you might want to go ahead and read them to make sure that those values are there and in addition, additionally you might want to compute the area in the perimeter. Once again, look at the syntax. Okay, there's one input argument here for the set with but up here if you look at the set with there are two input arguments why because the we want to make it as clear as possible that we are referring to the specific object and this is where, like I said when students first start out. There's got to be a delineation from the concept of a class versus the instance of that class you see the class is just the definition the class is telling Python hey I'm creating this brand new variable type. It's going to have these attributes and it's going to have these methods. Okay, but then when you get down to the nitty gritty of actually applying that class, then you have to instantiate objects to operate on them. So the object instantiation is, you know is already our two and we're setting these values. Well, of course, the syntax for saying look, I when I when I call this method I am specifically return referring to the object are to at the time that this method is being called. And that's what the self does the self says hey this in this particular instance, this is R2 I'm referring to an R2 I'm setting it's with equal to this value or I'm setting its height equal to this value. So once again you see the dot notation, the attribute we agree upon that that's defined that was defined a long time ago in the method. Okay, but that's why it's self dot height gets set equal to those values. So this again this takes some, this shouldn't take any getting used to because you've seen this type of syntax before. But now we're underneath the hood you're kind of seeing what the class definition actually looks like when you make these method calls. And then if we go ahead and run this you can see well now. Now R2 has access and is endowed with all those method calls they compute the area compute the perimeter, and then we can make these calculations like so. Okay. So now five times four is 20 or the perimeter if you just draw it out on a piece of paper, you know five plus four plus five plus four to compute the perimeter isn't is in fact 18. Again, so not a very interesting. Class definition but a class definition that really illustrates all the ingredients of what you need to have to to make the class definition work as powerfully as possible. And so, you know that's that's that, you know, or if you want to go ahead and use the rescale function maybe you want to go ahead and rescale, you know one of these so let's go ahead and now we're taking everything and multiplying the height and the width by two. And so you would run that and then you'd see that okay well now it's been the perimeter, you put a little print in here. The perimeter used to be, I'm sorry that the height and the width used to be for for rectangle R2. So notice we have a bunch of objects sitting around we've got our one, we've made no reference to our one except to set the value so far. We haven't made any computations but it's still there our one is still there even though we defined it a long time ago we defined it way way way up here right, but I'm fooling around with R2 down here doesn't mean but our one is still an object it's still a valid object. We could rescale it for instance if we rescale and take everybody and multiply it used to be five four, but now two times five is 10, and then two times four is eight therefore the area is going to be 80. And again if you add 10 plus 10 plus eight plus eight you'll see the perimeter is 36. So, so this example notice I just want you to notice look. And this is why it becomes in some sense my experience in teaching this is it's it can be a pain in the neck sometimes because you know you'll have you'll start to get these slides they get like invariably longer and longer and longer because you keep on adding more and more code to the method you know and it's easier for students to kind of lose the train of thought like I know what I'm doing inside of this and like oh let's add this method and let's add this method, but you got to you got to stay with the thread and this this I think that's probably the biggest challenge to teaching it live is that the examples, they grow like really fast and they can get, and that's why I'm just writing these really basic types of methods you know I'm trying to keep them to be one liners, because if they get too long. It just, it gets confusing and I don't want that to happen. So what's the big takeaway from the class definition but big takeaway is what's the syntax number one. Okay, so you need to know that second again all the all the the rules for Python syntax all the indentations right you've gotten you indent methods get indented and then stuff within the method definitions. Get indented as well so all the rules that you would expect would be true for Python all the colons all the indentations all the, all the syntax still remains true. Okay, still remains true. And that's good that's the way language should be it should be very consistent shouldn't you shouldn't be surprised by what you're seeing here. Okay, this should be very, it should be like a natural step it should be very obvious. And then of course there there are different reasons for constructing methods want one reason is to for the object instantiation you want to define that you want to control it you want to make sure that everything that you expect to do with that object is defined for example, within the method that there's no, there's no loose ends basically. And then of course you have your applications for the built in class definition, you know you want to compute stuff why you creating the object well I created the object rectangle because I'm interested in computing areas or I want to do some kind of scaling. And then finally, you know you have other methods that allow you to either set or get values attributes within within the class definition. So, so, so this has, you know, you know, it's a lot of what you would want to do. I think to to create a to create a class definition. So the rules for this, my expectation is if I show you something like this that you'll be able to generalize it, you know, to any, you know, to any class definition whatsoever. All right, so this is the basics. This is the basics. Now let's start to get, maybe a little bit more advanced. Okay, slightly more advanced because, you know, when you, if I go ahead and do something like this, let's say, what I'll do I'll just shove this down here. And I don't know what I want to delete just yet I'm just going to. I want you to know that that that nothing in Python has to be a secret. In terms of, in terms of, you know, what is always documentation, you know what methods are there for lists if you asked that the overarching question, you know, you could there's a lot of different ways to find this out but if I go ahead and just did a dir on creating a list. Okay, you'd see here that you get a, you get a long list of all the methods that you have access to. So this is powerful. Oh, you know, you can pop values off you can remove you can reverse the list you can sort the list, you can append, and then you see all this other stuff over here with these double underscores. I'm going back to this now, you know, what are these things do what's up with this why why do you have these double underscores or what are called Dunder, you know, Dunder methods. And the reason is, is because magic methods, or I'll call it I'll call the magic methods, or double underscore methods are methods that are going to run in some sense automatically in response to something that you've typed. Okay. So, let's just play a game here first I'll take this away so I just want to kind of unravel magic methods for a couple of seconds, because that because they're important and they're important to understand because they can do so much they're so powerful. And they've really been put there as hooks within the language. So that, so, so that, so that you can, in some sense, write code that would make sense for your class definitions. Okay, so let me give you an example. So, so you've got our one. Okay. And we've set our one to whatever values we set them to. Okay, so this is this instruction right here to print the object is a very common type of a thing like an introductory student would do that you've got our one and you want to print out its values. You know, and so, so you might go ahead and think okay well I'll just go ahead and use the print function. Well the print function is very smart who we said before, you know we started the print function eons ago is that the print function is is designed to handle is designed to handle variable built in variable types built in data types built in data class definitions within Python. So if you said print a list or print a dictionary or print, you know, a floating point number, Python's totally fine with that, you know, but now you have defined your own class. Okay, so what happened here. Well Python is going to try and survive. You know the goal is always to continue execution the goal is not to crash. So, so Python says well you want to print our one what does it do well just it gives you this hexadecimal, long hexadecimal number which is basically a reference to you know where the object is sitting in memory, which is which to an introductory program is completely meaningless and useless. But I'm just letting you know but Python's trying to do something with your, with your instruction, you know it's trying to help you. It's trying to do something so that you so that the world doesn't end upon trying to execute the instruction like this so so that's what it does to like I said to to a 105 program or this would be completely useless information. But at least it accomplished something. The question is, is it possible to apply the print function, if you will the built in Python print function to your class definition. And this is where a magic method could really really come in handy. Okay, well, if you're going to print something out. How do you want to print it out. What do you, what do you do what do you want to print it I mean you have to define what you want to do in order for the print function to understand what you're doing. A magic one magic method to handle string operations that will execute. So what will happen is is that print will see that you're making reference to an object, and it's going to try and help you. It's going to go to your class definition. It's going to look within your class definition to any magic method any Dunder method that deals with with strings in some way. In this case, I've got the str Dunder method. It's double underscore remember this is the syntax. And we're saying well when when you go ahead and attempt to operate on a string like using with using a print, print function, let's say, this will be the definition I'm going to put length is equal to string dot height, probably should say height there but whatever. And, and then, and then the width is going to be equal to. So it's okay for all you purists out there. All right. Um, and so we'll make that the height and and now we can come back and and run this print function. And it should say this. Okay, and everything's nice everything's good. Why did this happen well because Python gives you the power to, in some sense, redirect the print function to handle the string the way that you define it. So this is the power behind Dunder methods the power is is that is that they're and you don't do anything like you didn't you didn't call anything, you know, dot str you didn't use the dot notation to call the str method you didn't do that. What happened is, is that the, the magic method ran. And this is why they're called magic method, you know, is is it ran without you having to make reference to the str method you don't do that it runs automatically. The print function is faced with a dilemma. The dilemma is how do I handle this in the context of a string operation. And, and so, as long as you've defined that within your within your class definition and everything should go very smoothly. So that that's kind of the, when you go through the section on magic methods, you know, I want you to realize, as I tried to point out a second ago by using the dir on the, on the list class definition on an object of type list that you can see that there's a whole host of of magic methods that are at that are at your fingertips this is just one of many. And, and it's very, very powerful. Okay. So let's get I'll just continue on this theme for a couple more seconds because it's it's a big deal. Let's do something like this, just for the fun of it. You know, what if I did something like this here's a good one. I want to define a third rectangle that adds two rectangles together. And maybe what I'm thinking, you know, what I'm thinking in my head is naturally maybe well what I'll do is when I want to when I want to perform rectangle addition. I want to take the height of one rectangle and add it to the height of the other rectangle and take the width of one rectangle and add it to the width of another. I don't know why anybody would want to do that but the point is, is that this plus sign is against it's reserved for it has meaning it has it is, it has meaning within the built in Python language. And if there's some kind of a violation of that it's going to say hey look at you know this doesn't what you're saying isn't making sense to me here it's not it's not. I'm trying to add two things that that have nothing to do with my concept is what Python is telling you my concept of what the built in function for addition is. And, but so if you, if you wanted to add these together based upon that definition well then you know you would go ahead and maybe, you know play a game like this come back up here's another. So, for instance, the, the ad magic method, basically says that, and this, this is where we border on the concept of an object or into program what's called of overloading well it's not really an object or it isn't. The point is, is that when you have an operator. It's potentially it's possible to have many different meanings that would be associated with that operator. And it's the job in some sense of the computer language to try and figure out what you meant when you tried to use that operator. Okay, and that's what's called operator overloading. So you're using the operator in several different contexts, and based upon the data types, the computer language is going to make the decision help you make the decision say oh they mean they mean addition like this, rather than addition like that based upon the data type. Okay. Well, in this case if I'm using from from overloading the plus operator with two objects from the class of data type rectangle from the class rectangle. I'm going to define what that is so in this case what I'm saying is I'm going to define. I'm going to define addition rectangle addition to be adding the widths and the heights now watch this in slow motion. You know, I'm just calling this other for the heck you can call it a thing that you want to. But, but it's made this is making reference to self, and then the other rectangle. Okay, so by convention. Again, you gotta, there are nuances to every language, you know, there are subtleties to every language in this case, what Python will do is it'll assume the left operand is self, and then the right operand is going to be the other thing. So I called it other for the heck of it. And so you're so other is the input variable and then what we're going to do is we're going to instantiate the an object of type rectangle, right that is is going to be the addition of those two that'll contain the addition of those two heights and widths. So here's where the addition for the with argument comes in here's the addition of the height argument, how that comes in. Again so it's self dot height plus other good height. It's going to add them together it's going to instantiate a brand new, never before created object. You could do something like this and say okay well tell me what tell me what these values are so I have like a rectangle three and a rectangle three and three. And, and hopefully what we'll see here is is one plus two for the height for the widths and then three plus one for the, for the, for the height. So, and that's what it does if you go ahead and check down here, you have now defined or we have defined together some brand new. So, so again, the whole point I'm trying to make is that is that you have an immense amount of power and control over, you know how you want to operate on objects, and, and Python's trying to help you as much as possible to help you figure out how to use its own built in operators in some sense to redefine them in the context of the variable types you are creating. So we've defined a never before, you know, in this replete you know in this today's window, I mean somebody else on earth may have done this, you know already I'm just saying that that that you've defined, you know the ability to add to rectangles together so this is a different sort of the plus operator. That's where the term overloading kind of comes from. Okay. So, and then, and then we can take it even further maybe maybe I'll just do one more because we're getting short time I want to bring something else up before. So, so you can, there are tons of these you know and I'll just throw a whole, I'm going to throw a whole bunch at you know just to get the whole point across it let's let's go for the kitchen sink and then I'll get on to the next thing. So more, you know important, you know, magic methods, you know would be ones that redefine the greater than so so you can redefine not only arithmetic operators you can define relational operators as well which could be of some use, you can think about that as well so you can define greater than or greater than or equal to or less than or, or less than or equal to or, or equals. So I could come down here and I could ask the question now, I could say something like print R1 equal R2. Like if, let me tell you something if, if this equals, we're not here. Let's take it out, let's just take it out for a second, I'm going to take out the equals, and we'll just try printing R1 equal to R2. Okay, and in this case, well actually it's false for a different reason. Because, because that's not a good example, but let me just do this, because it's again Python is trying to attempt to understand what you mean by the equals but but in terms of this equals the use of this equals. Again, I'll get to spend more of an illness I just want to, and this is where I'll have to leave it because, but it's false the two are not equal so now the equals is actually being defined and you should play with this that you go back you should go back and answer this at the same time as to why that actually worked for R1 and R2, but it's not because this was redefined here I'm redefining the meaning of the word equals, and this is what's going to be used. All right, I'm going to have to leave it that I want to I want to move on to the topic of inheritance. So maybe what I'll do is is just come up very very quickly with this kind of a definition we'll go back to basics again let me get rid of all this stuff. Sure. I wanted to make sure it got to this to this topic. So here we go. All right, so the notion of inheritance basically this is this is important for for understanding object oriented the whole point of inheritance is, you know, you'll go out to the web and you'll find libraries of class definitions and you know there's just a notion of reuse like why why would you ever rewrite a class that's kind of similar to another class that uses a lot of those methods. Why not instead, you know, use the the kind of the larger concept class and then allow the sort of the lower concept class to inherit all the capabilities of that of that parent class. So, so in this case what I'm going to do is I'm going to call the rectangle class the parent class. And then I'm going to call, I'm going to a square is a rectangle square is a rectangle, a square is a type of rectangle, but a rectangle is not a square right so so so when you when you attempt to define inheritance when you have what you would call a parent class think of it as the rectangle and then a child of the parent class might be a square. That is so a square is a one when you have two class definitions where one has this is a relationship is a right is a so so a square is a rectangle when you have that type of relationship it means the rectangle would be the parent. And then you could think of the square as being the child of the parent, and therefore the child, in some sense should have access to all the stuff that the rectangle class could do. And then you don't have to rewrite it all over you don't have to like redefine another square class okay which would be in some sense inefficient as long as you understand the syntax for creating that child class. And then the inheritance comes in. So again, so I won't say again because I'm not going to keep this abbreviated. So the class rectangle notice when we define the class square. We're defining in a way that says okay well we have square and a square is a rectangle. So I'm going to place within these parentheses. Now this assumes that rectangle exists it assumes that the class rectangle is somewhere defined, you know, through through whatever mechanisms it's been defined so that so that so that the square can see the rectangle class in this case it can because it follows directly afterwards. Of course in this case we've got the init method and we've got the area and the perimeter and so forth. And then I just added, you know, another method that make believe that that you would want to define the ratio, you know, of the area to the perimeter again I just kind of put some calculation out there. The point is this though so here's a method that is confined to the child class square. It's not in rectangle. Okay, but notice also rectangle. Square has no, it has no init method. Okay, it could it could if you wanted to, but I'm just saying it doesn't. In addition it has no perimeter or area methods. Okay, but if I went ahead and I actually defined, say for example, to define two rectangles like so. Okay, and one is two by three the other ones four by five. I can I can call the area methods to determine the area of these rectangles now. If I decided further to define a square in a square you have to have the height equal to the width. Okay, so again, this is a very fast example I'm not I'm not checking or constraining, which you would if you were writing real software to make sure that this is really a square that the that the that the height is exactly equal to the width that's what a square is. And then of course I'm going to define I'm going to instantiate an object called exam three. Now watch what I'm doing here when the this object instantiation takes place. The init method is going to run automatically well which init method the init method from rectangle. And again, there's so much to go into with regard to the ordering of how the init would be called and there's a ton of stuff that would have to unravel for more, you know, an advanced, you know, introduction. But, but I just want to make clear that that when you when you instantiate the object square exam three. Okay, that that this exam is is running that init method from rectangle it's not running any method here in square it's running it from rectangle. And they're in addition because it's a child class, you're given access to the area and perimeter methods of the parent class as well why because the square is a rectangle. So you should be able to have access to, again, unless you write something unless you coded differently you have access to those to those methods and then finally now you can also call the method within defined within the class square. And so that's, that's what you would do and and and you get all these values. So six and 20 are the area of R1 and R2 which you do a compute the area is for and the perimeter in this case is is eight for example three why because these are two by two it's a two by two. So the, the area is two times two is for the perimeter is going to be eight and then the ratio of four to eight is equal to 0.5. So the whole point is that the child class has its own methods, but then it has access to everything within the parent. Again, unless there are other obviously unless there are other constraints which we don't have time to discuss. So, so this is another topic that was brought up that I think would be important. If you left an object oriented class understanding how, I mean this unit because it's an introductory unit with the ability to build a class, understand the net method understand a little bit about Dunder methods, understand a little bit about about calling and also class inheritance from parent or from child classes from parent classes. That's, that's a good introduction I think that I think that's a good starting point of material that you could take to any introduction to object oriented program being regardless of the computing language so so that's a lot this is a mouthful this is kind of like a fire hose today, but I hope that you gleaned something from it and it'll help to put that unit 10 in context and I'll stop there. Alright, well, thank you as always, Dr. Sack, there's some thank yous and you know good jobs in the in the chat for you there to well deserved I just last thing I want to mention before we go is that action next week at the same time, we are going to be doing a final final overall course wrap up so this that'll be a very good chance if you still have some questions having gone through all this you know leave them in the comment section below on this video or maybe on one of the other videos. We'll see if there's stuff that maybe we can get in that full course wrap up to people. So, hope everyone has a nice day and remember to check out the source, the course at sailor.org. Thank you.