Advanced Python Object Oriented Programming | Complete Python Developer 2021 course

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
everything in python is an object and in the next couple of videos we're going to talk about this idea of oop or object oriented programming what it is what it's useful for and why it's such an important topic for us to become great developers now when i say everything in python is an object what do i mean by this well remember our data types that we've talked about if i click run here you'll see that we have all our data types but we have this class keyword in front of it and i mentioned previously that this is something that we're going to get into now everything here is an object because in python everything is built by this class keyword and we're able to use different methods on our objects like this to perform some actions on them so what is an object objects have methods like these and attributes that you can access with the dot method now object oriented programming allows us to go beyond what python just gives us which are these data types but wouldn't it be amazing if we can create our own and make python even more powerful and using object oriented programming and what we're going to learn the class keyword we're going to be able to do just that so that the list over here can grow to our own custom objects now we're going to explore this topic of object oriented programming what objects exactly are and what this class keyword is over the next couple of videos but the key takeaway is that we're able to create our own types our own data types with different attributes and methods now why is this useful let's have a look at an example let's say we're working for amazon and amazon recently decides that hey you know what we're going to have delivery drones that are going to deliver our customers packages a lot faster but we need to code this drone right and up to this point we've learned that we can do that with basic functions conditional logic and just writing our code on a dot pi file but the problem is as code gets bigger and bigger and bigger it's not just one file it's not just 10 lines of code it becomes hundreds and thousands and millions of lines of code divided into different files code gets more and more complicated because we live in a world where technology is everywhere and programming something like a drone is quite complicated especially when it's a delivery drone so how can we use object-oriented programming to make this code more manageable well oop is what we call a paradigm that is it's a way for us to think about our code and structure our code in a way that is easier to maintain extend and write so if we're writing a program about let's say that does drone delivery well we break it up into small pieces into little objects that represents the real world for example i might code an object my own data type which is the propellers that allow the drone to fly and maybe another developer works on the camera and the vision part of the drone another developer can perhaps create the claws that hold the package and then another developer might be able to work on the signaling so that we're able to send signals from our drone to let's say amazon headquarters and know where all our drones are what we're doing here is we're breaking up functionality and data into different pieces that model the real world into separate objects so that different people can work on different parts and then we can just combine them afterwards and the beauty is when we want to let's say create a delivery system that's not a drone this time well it's a tank-like delivery robot we can use the same pieces such as the camera and the claw and maybe the signaling but we can just remove instead of the propellers and use the tracks that let's say tanks use and somebody else can code this part but we're able to use different pieces extend functionality from our drone into different objects now if you still don't understand a hundred percent don't worry we're going to go over this over and over throughout the next couple of videos the main takeaway is that oob is a paradigm a way to think about our code a way for us to structure our code so that as it gets bigger and bigger we're able to be organized because we're not writing silly 10 line codes we're writing millions and lines of codes companies like netflix have thousands of developers that are writing code every single day they need a way to structure and organize this code so that well it just doesn't turn into complete chaos and complete spaghetti code let's take a break and learn more about oop in the next video in the previous video we learned that oop is what we call a paradigm a way to think about our code and structure our code and i'm going to link to this excellent article from wikipedia about the history of programming languages you see we started with basic programming languages we had things like assembly language that was really low level really close to machine code we had things like cobol and then we slowly as we started writing more and more code in the 60s and 70s we started establishing some of these fundamental paradigms and one of the big paradigms that came to be especially with the small talk programming language was this idea of object-oriented programming or an object-oriented language you see up until that point we wrote what we call procedural code what that means is that if we look at a python file for example a procedural code was just like a procedure we simply had lines one through let's say a hundred and we just went from the top of the line to the bottom of the line we had conditionals maybe loops but everything was do this do that it was us telling the machine hey just do exactly this what i'm about to tell you with the introduction of object oriented paradigms this changed a bit we started saying hey let's model something in our code that represents a real world object for example if i'm about to code a car i would create a car object that has data on what color it is what type of engine it has how many seats it has but also actions like methods that we can take on it such as the car can go forward it can go backward it can open the door and instead of having these line by line procedural code we can think in terms of models real world blueprints because as humans we organize things think of a room think of a factory by organizing things and having different groups in a specific location working together that's a better way to think as well as to run things so how would this look in python well python is an object-oriented language or can be which means that it's able to support oop ideas this idea of objects and modeling and we've seen this when we use the type we see that everything is an object because we use this class keyword but what is this class keyword in python i can create my own data type my own class by simply saying class and then afterwards i can name it whatever i want let's say class big object now right away you see here that the naming convention is different than what we've seen before we're going to make sure that it's capitalized which is the standard we want to let programmers know that this is going to be a class and we're not using the snake case we're using what we call camelcase which is every new word is a capital letter and then here we use the colon and then in here we write our code now i'm not going to write the code right now i'm just going to pass but right there i've just created a new class so that if i do let's say for example type big object and i click run well i still get type because right now what we've created is this class which is a blueprint but we haven't actually created the object i know the wording can get confusing but bear with me i will explain this we can now create let's say object one equals to big object and then run this class so that if i do type object here object 1 and i click run i get class big object you can ignore the main here for now because we're going to talk about it later but you see here that i've just created my own object now let's think about what just happened here because it is a lot to understand you see in object oriented programming there's this idea of a class and an object now a class is this it's the blueprint the blueprint of what we want to create what are the basic attributes that is properties that our class has what are some basic methods or actions that our class can take and then from this blueprint i'm able to create different objects over and over using this as the building block so this blueprint is what we call a class which we define with the class keyword and this class can be instantiated that is the action of creating different instances and what are these instances these are all objects now the naming here is something that you're going to have to get used to and all object-oriented programming languages have this language so you'll just have to understand what somebody says hey i just instantiated a class it means hey i just created a new instance a new object so looking at this diagram let's go back to the code that we just wrote we've created here a class or a blueprint and then here this double bracket is us instantiating the class and saying hey class use whatever you have code in here and instantiate it and create a new object so we're creating a new object by instantiating this class and this is exactly what we're doing with something like a list right i can create multiple lists over and over and over and every time i create a list i have access to all of these methods and sometimes even attributes that i can use and this way i save a lot of time instead of coding it myself and in the same way i can create multiple objects here object two object three just like that and now i have three different objects that i can use based on this blueprint now the blueprint right now doesn't have anything because well i can add code here later and we're going to do that in the next video but the beauty is let's think about efficiency here you see the blueprint itself the class is going to be stored in memory so python interpreter is going to say hey big object it's going to be the blueprint for this so i'm going to store all that code in memory but every time i create an object i don't have to rewrite the code or do anything like that i can simply say hey go in memory to where big object is and just run that code so that again we're keeping our code dry we have one place that allows us to instantiate our code into objects let's take a break and expand on this class in the next video now the best way to learn is to actually see code in action so enough theory let's actually code our own class i'm going to just delete everything and start from scratch and let's say that we're working for a gaming company and this gaming company has well this wizard game that they want to create almost like harry potter now how can we think about it in object oriented programming well the first thing that we're going to need is we're going to have to have players right each player has a character that they need to play so let's create a class here and call it player character again notice the naming convention because it's a class and another rule is that usually you want it to be singular not plural so you can't say player characters because i mean it's a blueprint from this blueprint we're going to create many characters but those are going to be objects so player character single and singular now in here i'm going to do a few things and i'm going to warn you this is going to look confusing at first but bear with me i will explain it we're going to define a underscore underscore in it underscore underscore now in here we're going to say self and then give it a name the name of the character from here we're going to do colin once again and simply say self dot name equals to name oh boy what just happened here again i'm going to hold off explaining what this does and just write a few more lines of code so that it makes a little bit more sense i'm going to write another method in here and i'm going to define let's say a run method that each player can run and in here i'm going to once again have this weird self word and then simply inside of here say print run all right so i've just created this class it's still kind of confusing we don't really know what this in it is what the self is and this whole new look but let's ignore that for a second and simply say player 1 is going to equal player character and instantiate that player so that we can print player and see what's up with this player if i click run all right i get an error it's a type error it says init missing one required positional argument name all right let's take a break here and see what is happening here you see this init method is a special method you see the two underlines here this is called a dunder method or a magic method and we're gonna have a video specifically about this but when we're building a class you usually see this at the top and this is what's often called a constructor method or an init method and this is automatically called anytime we instantiate remember instantiate means is we're calling the class to create an object so when i do this it's going to automatically run whatever is in this code block so when i run this you see that i'm getting the error on line 9 right here on line 9 and when i try to instantiate the player character it runs init and then it tries to do self.name equals to name but the problem is that i'm not giving it an argument name and that is because when we call init we accept whatever is after self as the parameter name so we need to give it a name of this character so let's say the name is cindy if i click run here all right it looks like i have a player character and as a matter of fact it even shows me that it's an object at this memory location so on our computers this is where the player character player 1 is located now very cool but what is this self keyword and what is this code on line 4 this is a way for us to define well self self refers to the player character it's saying hey this is going to refer to this player character that we're going to create player player1 and i want self.name to equal whatever the parameter name is so that if i do player dot name here and i click run i get cindy and why is it cindy well because i gave it the parameter player character and when i instantiated it i passed the name parameter the default parameter itself when i do init and in classes you see here that the default always the first parameter where we're defining a method is self and now i give name to self dot name what if i remove this here and i click run you see that it says object has no attribute name because in order for me to say hey i want player to have a name i need to say self dot because self refers to player one so if you remember when we had a list we had to do dot and then we would say append well somebody wrote this append code and in the append code it's going to say self dot let's say add to the list and self refers to whatever is to the left of the dot so this way it allows us to have a reference to something that hasn't been created yet in this case player one and let them know that hey when it's created when we instantiate then i want you to make sure that player 1 has this name attribute so that if i created another player and player tom is going to be player 2 if i print player2.name and i click run i have two different players with two different names i was able to use the same piece of code but have different values because the self every time i instantiate this refers to first time player one then first second time player two now self is one of those things that gets really really tricky to understand and you might need to watch this video a couple of times but the key here should be evident to you that is i'm able to write code only once remember our principle dry do not repeat yourself and i'm able to make it dynamic by saying this data that we're going to create for the object is going to be dynamic and it's going to change based on what we give it so that i can create different players with different attributes but still use the same code now i can have multiple things here i can have age for example and once again i can say self.h equals age and then cindy will have to pass let's say 44 and tom is 21. so that here once again if i do age they'll have different attributes so remember these are attributes or properties that these objects have and you can access them by doing the dot notation and then accessing the property itself you see that i don't have any brackets here because it's not a method it's not taking action it's simply saying hey i want to access this attribute if i do dot here my editor will actually tell me and will have the symbol for hey you have access to the attribute age and name and as a matter of fact i also have access to run the method so that if i click run well remember a run is a method so i get this bound method but it's not printing anything it's not taking the action so we have to once again add the brackets hit run and look at that i'm able to do run then i get none then 21. why do we get this none because remember this is a function that doesn't return anything when a function doesn't return anything what do we get we get none so maybe i can just say return done if i click run there you go we have run done 21. now one last thing before i end this video the interesting thing here is if i do player 1 and then player 2 and i print this and i click run you'll see that i get the player character but the object each of these objects player 1 and player 2 are at different memory location so i'm able to use one piece of code one blueprint to create multiple players but these players are not the same they're created from the same blueprint but they live in different places in memory and that makes sense right we don't want tom and cindy to be the same player they're two different players so this way we're able to keep things safe and anything i add to player 2 for example let's say player 2 can now attack and attack will just be a property that will be 50. now if i do dot attack here you see that player 2 has attack but if i do player 1 dot attack i'll get an error object has no attribute attack i hope you're starting to see the power of classes although it may be difficult to understand at first the power becomes evident when we are able to create this blueprint that we can now use over and over and over to create our own objects let's explore more in the next video object-oriented programming allows us to create objects that have their own methods like run and attributes properties it's a great way to add more functionality to a language and mimic the real world for example we use the idea of working for a gaming company although python only gave us a few data types i was able to create a player character and now my boss is happy because this player character can be used all over the game and all other coders have to do is run this line with the custom name and age of the character so oop allows us to write code that is repeatable well organized and also memory efficient right because we only write this once so if you want to be a great developer oop is something that you need to know and you need to understand because well this is how you want to organize your code thinking less procedural and thinking more in terms of functionality grouping data like attributes together with methods to create this class that is able to mimic something from the real world now i want to show you a useful tool here we saw that when i do player dot my editor shows me what i have available the properties as well as these purple boxes which are the methods that i have available and right off the bat you see that i have age name and run but then i have all these other ones that i got by default now these are all dunder or magic methods which we're going to get into but the key here is that if i do something like help which is a new function that you may have not seen before and let's comment this out if i click run i actually get well the entire blueprint of the object if i do something like a list and i click run again it shows the blueprint that it has and this is a great way to see what class blueprint some of the python data types have now this is something we'll revisit later but i want to go back to this this player character now in here we saw that we're able to create attributes and attributes are pieces of data that are dynamic that is when we instantiate an object they are going to be unique to that specific object like name and age and we have to use this self keyword to make sure that it was dynamic however there's another thing called the class object attribute and it might look like this let's say we had the player character and they had to let's say be a paying member in order to play this game you have to have played or you have to have gotten a membership so let's have a membership equals true attribute now unlike this one you see that it's on the same line as our methods and this is called a class object attribute and a class object attribute unlike these regular class attributes is different because well it's not dynamic it's static so if i click run here and we want to make sure that we print something so let's print player two and i click run well i get the player that's great but if i do dot membership and i click run look at that i get that equal to true if i do player one here as well and i click run i get true again so all the players have membership set to true but this is not dynamic it's a class object attribute which means it's an actual attribute on this class and this is something we use when there's no change this is going to be true and exists for all objects so you can't really modify it it's just all the objects that we instantiate will have access to it so this doesn't change across instances and we can use this down here as well or anywhere in this class blueprint as a matter of fact for example let's say we wanted to check if membership exists so we're checking if membership is true which i mean it always is so this is a little bit redundant but in here i can say only if membership is true then i'm going to assign name and h but in order for us to access membership i'll have to do self dot membership because remember self refers to this player character so that if i run this everything still works and if i do player 1 dot name this still works or i can refer to this by the actual player character so playercharacter.membership so if i click run here this also works because it's a class object attribute if i were to perhaps in the run let's change this to shout and in shout it's going to want to run let's remove this line it's going to print an f string that says my name is and give it a name do you think this will work let's give it a try let's say shout and make sure we run that method and then click shout again if i click run i get an error name is not defined on line 11. if i go to line 11 here name is not defined why is that well because we haven't used self so let's do self dot name and if i click run there you go my name is tom my name is cindy okay awesome and i'm able to use self because i pass it into here as the first parameter and all methods receive the first parameter as self so that we can use them but could i just do player character dot name if i click run i get an error player character has no attribute name now why is that because name is not a class object attribute it's not actually a property or an attribute of player character no it's defined in our constructor function our init function so that's a bit of a gotcha here and something that you'll have to get used to a class object attribute is something that doesn't change across different instances versus an attribute or a class attribute is something that is dynamic and specific to each class object the way we access them is different where we can actually access membership like this but in order for us to access a name or age anywhere inside of our class we have to use the self dot name which is why anytime we create a method in a class even if i create a new one over here and let's say this new one is going to be run well once again i have to use self as a parameter and then anything else that i want to add in here as the second parameter so that when i click let's say run i pass in the hello argument like this i know this is a lot but hopefully you're starting to follow the rules of classes once you remember these rules then it becomes easier and easier but we'll practice this a little bit more in the next video i want to add a quick note about this constructor function remember this gets called every time we instantiate an object and this is how we create custom objects right but an interesting thing that you can do here because you have control over how the instantiation happens you can do different safeguards for example let's remove this for now because we don't need it or actually let's change this to let's do h we want to check if the user is over 18 then we're going to run this otherwise well the program is going to error out because we only let people age 18 and over to play the game because let's say it's rated r so we can do different things in the constructor to make sure that we are instantiating the object the proper way we can also give default parameters like name can be anonymous if we wanted to if they don't provide a name and then age will be let's say 0 if they don't provide an h so that here let's say i forget to instantiate player 1 and player 2. if i click run i get an error player object has no attribute name and this is on line 11. now why do we not have self dot name well because on line 17 we're trying to call shout but unfortunately we never instantiated this because when we don't provide anything the age is going to be zero so we're never going to instantiate with these properties okay so let's just give it tom and then age is going to be 10 and let's just remove player 2 for now if i do player 1 dot shout and i click run once again i get an error because well tom is only 10 years old we're not going to create this character now we're going to talk about errors and maybe instead of just having this error out we can send a message saying hey player is not old enough but for now i hope you see the power that comes with this idea of constructor and the instantiation of an object where we're able to add these different controls and safeguards to perhaps make sure that we receive the right data type in order to create the object or maybe the age is over 18. in order to make sure that when we actually instantiate this player1 object we're doing it the right way so this init gives you a lot of control welcome back we learned that we're able to create an actual attribute for the class but what about a method is there a way to do something like here what we do with attributes but for methods well there is and we use a decorator which is a topic that we'll cover later on and you'll understand how these work underneath the hood in a bit but for now the syntax that we're going to use is the add sign and then we call a class method like this and now with this decorator we can now write a function for example let's create a function and we'll call it adding things that will take num1 and num 2. and in here oh make sure we have the define for the function and in here we'll just return num1 plus num 2. okay so what does this class method do let me minimize this just so we can see a little bit better now in here let's see if player one has access to adding things so let's just say adding things two and three if i click run takes two position arguments but three were given that's on line 17 so when we call this we gave it two parameters but then it was expecting it says that we actually got three and that is because adding things the first parameter just like we have here is the cls and cls stands for class so this player character that's the class that we're referring to so similar to what we've seen before but the standard is to use cls now if i run this you'll see that we get 5. okay but looking at this it looks like it's pretty much the same as the above except instead of using self we use cls but how is this a class method well it's because we can actually use this without even instantiating a class let me show you let's say that we don't instantiate player1 and now i just simply call in here player character dot adding things if i click run look at that i get five it's a method on the actual class it's a class method so you can do some interesting things and by the way class methods aren't used as often so if you're thinking hmm why do we even need this well i would say 95 of your classes aren't going to use something like a class method but there are cases where this might be useful for example we can use the cls to actually instantiate an object in here so for example i can say that cls which is the class which is the player character and i'm going to instantiate it remember just like we did here with the brackets with num1 plus num2 as the second parameter and we'll give it name teddy if i hit run here look at that i've instantiated an object teddy with the age of what should be five so let's take this make this equal to player three and if i do player three right here dot age and i click run i get five so i have a whole new player here that was created by using this class method so i was able to create just like i created a class object attribute a class method using this at sign there's also one other way of doing something like this which is the static method and the static method works the exact same way as here except you do not have access to the cls for the class so you can't do something like we did above instead we just perform some sort of method like adding things to like this so the only difference between the two is the idea that we don't have access in our parameters to this cls so we would use something like static method where we don't care anything about the class state a class state is something like these we don't care about the attributes really we use something like a class method when we do care about these attributes and maybe we want to modify them or change them now this class method and static method is something that you won't see very often but i wanted to show to you just because you might encounter it through your python career hopefully this wasn't too confusing in the next video i want to review what we've just learned up until now welcome back up until this point we learned that oop or object-oriented programming is a paradigm a way for us to think about structuring our code we went from procedural to writing functions to now using things like object-oriented programming now what we've seen is what we call a classical oop that is we use classes to incorporate object-oriented programming paradigms we learned that we can create a class in python with a class keyword using this naming convention which is camelcase with capital letter which tells other programmers that this is a class that needs to get instantiated we learned about class object attributes we learned about how we can instantiate an object and how we have this init function that runs on every instantiation to customize our objects we learned about how to add methods to our class so that each object that we create and instantiate has access to these methods we also learned that there's things like class method and static methods which are methods that can be called on the class without actually instantiating it into an object and all of this was that so we can create our own data type that models the real world now there's still lots more to learn in object oriented programming but if you follow these guidelines and look at this overall structure that's pretty much it that's how classes work in python and we actually have gained a really powerful tool now to really make our code better now the idea of object oriented programming requires some practice and it's really hard to grasp when you're just starting out we're going to try and do some exercises and learn a few more things about object oriented programming so that we can really grasp this concept and use it in our everyday programs i'll see you in the next one bye-bye welcome back to another developer fundamental what is it it's to test your assumptions what do i mean by this well anytime you learn something something new maybe something i'm teaching you or something other instructor or book or resource is teaching you you want to test your understanding and your assumptions because you don't want to have any magic black box that things are happening that you don't understand you want to know how things are working so you can explain it to people for example remember how i said that self is referring to this player character class how can we test this assumption with code well if i had just learned what self is what i would do is to say to myself well i want to see self i want to know what it is you know what i'm going to return here self and actually see what's going to give me right i it's code i can return self if i want to well let's do that let's create this player character yes i'm a hundred years old and then here we'll do player dot run let's do a print here and click run all right so the self is the player character that i created which is player one which is located here okay so although this is a simple example what i'm doing as i'm learning is to test my assumption is that what i expected before i even run this code i like to think in my head what do you think is going to happen and if there's a mismatch and i get something returned that i don't understand well then maybe i look into it for example this underscore underscore main i still don't really know what this is why is it is this here i mean it has to be there for a reason right and that's something that we're actually going to talk about later on in the course when we talk about modules so hang in there but the way that learning happens in an accelerated fashion is when you don't just take my word for it because if you do that you don't fully grasp the concept the idea is to test and test yourself as well in your understanding and say if my assumption is that self is referring to the object that we create how can we test it and this is a great skill that a great programmer has so hopefully in future lessons when i'm teaching you something you test those assumptions you test your learning through methods like this i'll see you in the next one bye-bye welcome back what i haven't told you is that when learning about object-oriented programming again and not just in python but in any programming language that supports oop paradigm is this idea of four pillars of oop the four things that object oriented programming does really really well and as a matter of fact we've actually learned the first one and that is the idea of encapsulation what is encapsulation encapsulation is the binding of data and functions that manipulate that data and we encapsulate into one big object so that we keep everything in this box that users or code or other machines can interact with and this data and functions are what we call attributes and methods right we're able to encapsulate the functionality of our player character by having name and age data or attributes and also have functions that can act upon this name and age so for example i can have a method in here that says shout or speak and the speak method can now use the name and age i can say my name is self dot name and i am self dot age years old so that if i do player one dot speak and i run this my name is andre and i am a hundred years old i'm encapsulating the functionality if i didn't have this class i would have well some variables and then two functions but by using encapsulation i've packaged this up into a blueprint that i can create multiple objects of so that when other people see my code they know hey this is an entire object that i can interact with i can use in certain ways that player character describes and we've also seen this in our built-in python data types right when i create a string like this because of encapsulation i have all this functionality available to me all these methods that i can access so that if i do let's say capitalize it will capitalize all my strings i have all this functionality encapsulated for me to use now why do we want to package data and functions into attributes and methods well because this gives us extra power right if for example this player character doesn't have any actions any methods and just had attributes well in that case this is kind of like a dictionary right it's kind of useless if i print player one here and i click run i have this player object but i can access name like this and i can also access age like this but i can't really do anything to it i could have the same dictionary here let's say player two that is going to equal a dictionary that has name of andre and then age of 100 and the only real difference between the two is the way i access this information instead of the dot notation i use the bracket notation to access the keys so that when i click run oh i have to make sure that i do two here for player two if i click run again it's the same thing sure i can do it this way but it's kind of useless why not just create a dictionary if all i want is data but using this way i'm combining things packaging things up into those instances into those boxes that can be useful and also things that have meaning right because our world is full of data and actions right even a tree for example if we had a tree class in our real world the tree would have maybe whether it was an evergreen or a perennial it will have whether it has lease or it doesn't how tall it is i'll have all that information but also actions right i can cut down a tree the tree can grow the tree can extend its roots so this way we're able to mimic what happens in the real world with our code so that is encapsulation and we've seen it but let's talk about our second pillar in the next video we know that there's four pillars of oop and we learned about encapsulation what's the second one well it's called abstraction an abstraction means hiding of information or abstracting away information and giving access to only what's necessary so whatever the user or the programmer or the machine is interested in that's the only thing we give access to everything else we kind of hide it in a blanket underneath the hood because our users don't have to worry about it let me show you what i mean if i go back to our old example here so instead of having a dictionary we actually have a player character with a bunch of methods now abstraction can actually be seen here right when i do player 1 dot speak you're seeing abstraction in action because when i click run i get this string but when i call speak i don't really care how speak is implemented all i know is that player 1 has access to the speak method and i can use it same with when i'm using something like a tuple right if i have 1 2 3 and i do dot here i can do count to count how many items are in the tuple so if i do print and click run well i have to give it a thing that we're looking for in our case let's look at one and let's add another one in here if i click run i get two now do i need to know how the count method was implemented no i mean i can go look into it i can look at the python documentation maybe the python code and understand how it's actually counting this but i don't really need to right if we try to understand every single little piece our heads gonna explode sometimes all we need is a method or an attribute and just get access to it without having to worry about how it's being implemented which is really really nice the same goes with built-in functions right if i do length here and i click run i get a length of 4 but i don't really need to know how length was implemented in python it's abstracted away from us and this is the power of oop it abstracts away things that we don't need to care about or at least it makes us more efficient so that we know that it works a certain way and we're not wasting our time learning or coding from scratch if we had our iphone for example well the camera feature on an iphone it'll be nice for an app that we build to use it but we don't need to actually know exactly how the iphone camera is coded on an iphone no instead the iphone usually gives us a way to say camera dot take picture to actually allow us to take a picture without knowing how the apple engineers actually coded the camera so it's a very powerful concept okay so you're thinking i think i get abstraction but let me ask you this could i just do player1 dot name equals to let's say exclamation marks and then player dot run or you know what let's do speak equals to boo make sure it's player one well if i now print and do player1 dot speak and i try to run this function let's see i get string object is not callable because speak has been modified speak has been modified to a string value instead of this actual function that we would have needed so that if i run just checking the speak attribute i get boo hmm i mean abstraction is good but hold on a second here this is bad if i have a class that i've abstracted away but anybody can come along any programmer can come along and just remove all my hard work and overwrite it like that isn't that bad let's take a break and explore this topic a little bit more in the next video welcome back in the previous video we saw that we did some big boo boo that is we overwrote name and speak and now all that hard work that we put into our class has been overwritten by this i mean sure if we instantiate a new object we will have our run and speak but player 1 now is completely useless it has no name and speak well it just says boo completely useless now in python there's this idea of public and private and this is related to our discussion of abstraction the idea behind abstraction is that we hide away information and only give access to things that a user is concerned about right so ideally we shouldn't have access to init ideally we shouldn't be able to let's say modify run or modify name and h because when we create a player character in our game hopefully the player can just randomly change their name or their age and sneak into our game that perhaps is only 18 and over so can we make a private variable in our class well here's the thing some languages allow us to have private variables for example in a language like java i can actually say that an attribute is private like this and i won't be able to access it and modify it like i have this way but in python there's no true privacy no true private variables so how do we get around this well what we would do is do underscore name or underscore age now does this give any special power no this is just a convention that is as programmers as python programmers we determined that hey if we see underscore in our code that most likely means that this should be a private variable so that when i use it and speak let's say underscore name underscore age and let's comment this out if i click run well i have to run this because now it's a method let's click run and i get my name is andre and i'm 100 years old it all works but if i try to overwrite these and click run oh and now because it's no longer a method let's remove speak and i click run this still works and that's because like i said there's no true private variables as programmers we've decided that underscore means that you shouldn't touch this please don't touch this you can still be bad and do something like this but i'm letting you know ahead of time if you see underscore this shouldn't be modified this should be private and that's how we achieve privacy in python we all kind of agreed to say hey let's keep this little thing private so if you ever want to keep a method or a an attribute private you just put an underscore in front of it but it's no guarantee what about this double underscore init again this is something we're going to be speaking about very shortly but it's called a dunder method that is it's built into python and we usually never write our own dunder methods we would never write double underscore like this these double underscores and there's lots of them have special meaning in python and the reason that they're named like this is because they're saying hey if you're writing double underscore for your variable you're doing something very wrong you're about to overwrite something so once again this double underscore is also a convention to let people know you shouldn't really touch this or modify this with each data type let's say a list if i do dot you'll see that as you scroll down you have a lot of these dunder methods again something that we're going to talk about but these are here to let you know don't overwrite these if you're doing something like underscore underscore i don't know doc like this that's bad don't don't try and modify it and assign it to five so this idea of a private field is important to python and although we can overwrite a lot of things it's bad practice but let's bring it back to abstraction the idea is to abstract away this code and although it can be modified and overwritten by using these proper conventions like private attributes we're able to abstract things away but still make sure that whatever the user might be using isn't going to break our code i'll see you in the next one bye-bye so we've talked about encapsulation about abstraction what about the third pillar of oop it's called inheritance an inheritance allows new objects to take on the properties of existing objects so you can inherit classes let's have a look at an example let's remove the previous code that we've had and go back to our game example we want to create a new game and we have different types of users so we have users that can be wizards that can be else that can be i don't know archers but all these users have some common functionality and each one of the sub users like wizards elves archers have some common shared functionality but then again different maybe attacks so using oop we can actually do inheritance for example let's say we have a class user here and this user will have let's say a sign in function or sign in method once again it's going to receive self and then we'll just for now assume that we have some sort of a sign in here so let's just say for now print logged in because in order to play a game they have to be logged in okay now you might be wondering where is the init method here shouldn't we have that init method that gets run first well we could but if we don't have any variables or attributes that we want to assign to the user well in that case we wouldn't need an a method so for now we'll just say that we don't need there's nothing that the user has other than this sign in method now let's say we want to create a bunch of sub classes so that we have a class wizard and for now we'll just do a pass here so that we don't have an empty class but it will still allow us to build it and then let's say we also have a class archer that will pass through as well oh make sure we have brackets here now here's the thing ideally all these wizards and archers are users as well right so we have users and these users can have multiple forms they can be wizards they can be archers they can be ogres all the characters in our game but all of them let's say have to be signed in first how can we make sure that all of these users or classes also have access to sign in well we can use inheritance and how do we do inheritance quite easily actually all we do is in the bracket pass the parent class that we want to inherit from so let's say i do user here now let's click run here no errors everything is looking good and by the way you see the green line here tells me that indentation is not a multiple of four because indentation should be four in python so we can just do this but i like keeping it smaller just so it's easier to read okay so let's instantiate a class here i'm going to create a wizard one and then say wizard and run that wizard class now if i do print here and i do let's say print wizard if i click run i see that the wizard object has been created and what if i do dot sign in i see that yeah it's actually there if i do sign in and click run hey i'm logged in how cool is that i inherited from the user class this functionality and this is really really powerful because now i can extend my wizard right so let's say that this wizard has an init method which will be run when the wizard is created and we'll have a name and power that we get and in here we'll assign self name to equal name and then self dot power to equal power and let's also add another method calling it attack and this attack method will simply print an f-string that will say attacking with power of let's say self dot power and then we're going to do the same for the archer so i'm going to copy this code paste it in here and the archer will have name and let's say instead of power we'll say that it has let's say number of arrows and number of arrows will be the new attribute that it gets and then the attack will have well attacking with arrows and then we'll have arrows left and arrows left we'll just say number of arrows and we can do something fun where the arrows decrease as every time you attack okay so now that we have this let's make this a little bit smaller just so you can see there you go now that we have this let's instantiate the first wizard with let's say merlin with a power of 50 and then the archer will be instantiated as robin with let's say 500 arrows or let's do 100 errors so now the wizard and the archer are going to have well they'll have the sign in but they'll also have the attack but unique to their individual classes and they'll also have different properties let's have a look if i was to do wizard dot let's do wizard one dot and then we'll say attack and let me just turn back my code intelligence we'll see that we have a few errors here what's the what's it say undefined name self and that's because i forgot self in the brackets so you remember we always have to give the first parameter self if we scroll down we go to wizard dot we see that we have name power and attack if i click attack here and i run we see that i'm attacking with power of 50. if i do archer 1 dot attack in that case i'll get attacking with arrows errors left 100. but both of these have the sign in function at the same time how cool is that this is the power of inheritance we're keeping our code dry right we're abstracting away the part of the code that they both share but then changing things according to what each one needs so for example i could have different methods and properties on wizard than the archer but also have a shared user's user functionality that they have and this way it keeps our code organized and clean now let's bring back the zoom in just so you can see it clear now this idea of inheritance is really really powerful and the key here is that we have a parent class and children classes now sometimes these children classes are called subclasses or derived classes because they're subclasses of user or derived from the user class let's explore this topic a little bit more in the next video now i'm going to minimize this a little bit just so we can see a little bit clearer it's not as messy this way and i'm going to remove some of the spacing in between here even though i'll give us a warning just so we can see everything there we go all right so we have these classes now python gives us a useful tool to check if something is an instance of a class and easily enough for us it's called instance or is instance and is instance is a built-in function in python we give it the instance and then the class that we want to check so in our case if we had wizard 1 equals to wizard merlin with power of 60 in that case if i do wizard1 and then do class wizard and i print this what do you think we'll get if i click run i get true because wizard is an instance or wizard1 is an instance of wizard let me ask you this what if i do user is wizard1 an instance of user guess what's about to happen it's true right because wizard class is a subclass of user so technically yes wizard1 is an instance of user because we've had to run this class to create wizard1 but here is the interesting part if i do wizard one dot do you see how i have our methods and attributes that i've added but also all these dunder methods that we haven't really talked about yet where do these come from right well in python remember how i said everything is an object well everything in python inherits from the base object class that python comes with and it's called object you see how it got highlighted here so if i do is instance wizard1 of object oh and i have to remove the dot over here let's click run it's true because wizard 1 inherits or gets methods from the wizard class from the user class and even higher up from the object base class that python comes with and that's why we have these automatic methods attached for us so that using object every single method that is useful for example if i open up a list if i do dot and let's say we pick the repr method which we don't really know what it does yet but if i go to wizard1 and i do dot you see that i have it as well because they both inherit from the object base class and this way we avoid repeating code any common functionality i can just dish it out to all the objects that need it which is very very cool so underneath the hood when i do something like user it's actually accepting object as the parent class in order to accept these properties that are built in and that we might need in the future all right that was a lot one more pillar to go i'll see you in the next video bye-bye one final pillar of oop to go we talked about encapsulation about abstraction and about inheritance and then there's this fourth one that has a pretty tough word polymorphism what does that mean well poly means many and morphism means form so many forms now we know that methods belong to objects right we use the self keyword to act upon the object that got instantiated now in python this idea of polymorphism refers to the way in which object classes can share the same method name but those method names can act differently based on what object calls them now that sounds extremely confusing so let's have a look at a code we have our user wizard and archer classes and as i mentioned with polymorphism different object classes can share method names so we have attack here that is shared but each one does something different based on the attribute for example when i do wizard1 attack so let's do that wizard 1 dot attack if i click run i get attacking with power of 60. because well wizard has a special meaning to its attack versus archer they're different so although they share the same method names because of the object that's calling it the output is going to be different so we can actually do something quite interesting here let's say that i have wizard1 and then we'll also have archer one and archer one will be robin and robin has 30 arrows now what i can do here is actually call them in different ways for example i can create an entire new function called player attack and this player attacks takes a character and in here we can say character dot attack and now if i run this code and say player attack wizard 1 and i run this i'll get attacking with power of one if i do player attack i have archer in here if i click run you see that the same function gives me a different output even though we're calling the same thing because of the object that we pass into it polymorphism another way to demonstrate this is if we do a for loop if i do 4 let's say character in and let's add wizard1 and archer 1 into a list and if i print here or let's just run character dot attack if i click run here once again i have two different outputs even though i'm calling the same method because of the different objects and this is a really powerful concept right because we're able to customize this according to our specific needs even if let's say that the user had a attack method and this default attack method is let's say print do nothing because it's just a user even if i run these let's say print wizard one and let's say dot attack if i click run it's going to override whatever the original attack was because we already have that method in our wizard class but let's say i wanted to have both user and wizard run the attack method how can i do this now this is something we'll explore a little bit more in the next video but for now i can say user dot attack and give it self because i accept user as my parameter in here and then i can run user dot attack so let's see what happens here if i click run i have do nothing and attacking with power of 60. so polymorphism allows us to have many forms it is the ability to redefine methods for these derived classes that is wizard and archer and an object that gets instantiated can behave in different forms in different ways based on polymorphism and this is useful because we are able to modify our classes to our specific needs but also not have to repeat ourselves in case we want to use something like attack from user inside of wizard so there you have it the four pillars of oop encapsulation abstraction inheritance and then finally polymorphism now no amount of videos or books are going to teach you exactly when to use what however the idea here is to understand that these powers exist with oop you're never going to say oh i need to implement polymorphism no most of the time you're just coding along and it happens that you're coding in a way that emphasizes polymorphisms this is just the power of oop although these are big words at the end of the day we've learned how to use them to structure our code in a way that is efficient and clean and that's the whole point it's all about organizing our code now some of you may have been a little confused when i did this user dot attack self in the next video i want to explore this a little bit more i'll see you in that one bye welcome back in the previous video i showed you how to call a method from a subclass of the parent class so in our case we did user.attack in order to run the attack method in user now i've removed the attack method from now because i want to try something different i want to create a init function in here and this init function will take self and then let's say that the user will receive let's say email because all the users of our game need to have emails and in here we'll just say self dot email will equal the email nice and simple now in here if i was to run this code and let's remove user.attack for now so we have the same wizard we've just added this or sorry this init and we have our wizard1 so if i run wizard here and let's say we want to run wizard1.email if i click run i get wizard object has no attributes email but i thought the user is going to be called when we create the wizard right when we instantiate wizard1 well the thing is although we might inherit let's say for example if i do dot we might inherit the sign in from the user and if i click run we see that we inherit that the wizard already has an init function already a constructor right so how can we solve this well one way is to just add email here right and just have the email attribute just right down here but what's the problem with this well it's inefficient right because if i create an archer class i'll have to do the same thing and when we know that all these attributes are going to be the same on all of our subclasses we want to do it here so what's a more efficient way of doing this well we want to call the init method of the user from inside here right because every time we instantiate a new wizard well this init function is going to be called so the way to do that is to say user dot underscore underscore init and then give it the self and then email and then the email is something that we pass in so that if i did go down here i can say merlin at gmail.com is going to be the email so that now if i do let's say dot email for wizard1 and i click run i get merlin's email once again all we did was we called the init method of the user inside of the wizard so when we instantiated a new wizard we ran this function and inside of this function we ran the user.init and passed in the email that we passed in as an argument in here now this is one way of doing it and then there's another way and it's called super and it's a keyword as you can see it's being highlighted here and all we do is run super and super is referring to the super class or the class above wizard which is user and this is actually a new addition as of python 2.2 with super we actually no longer need the self so our code looks even cleaner and all we pass is this and if we click run we still get the right answer super allows us to refer to user this way and not have to worry about passing self welcome back i want to talk to you about this idea of introspection and introspection in computer programming means the ability to determine the type of an object at runtime what is runtime that is when the code is running you can determine the type of an object and it's actually one of python's strands because everything in python is an object we can examine we can introspect an object and actually figure out what our code does as we're coding and then running and python allows us to do introspection and inspect these objects with some nice helper functions this one function is called der and der well if i run this will give me all of the methods and attributes that the wizard instant has so with a dir function we give it an instance and right away we get access to what it has access to well we see that we have name power and sign in again we have the sign in from the user and then we have also attack from the wizard class and this editor that i'm using whenever i do dot is actually using this ability of introspection to just list out these available methods for me just like i have here so this is really useful when you're trying to figure out what you have access to but you may notice something here we have a lot of these dunder or magic methods that we haven't really talked about what are these and why are they so important in the next video we're going to tackle this question i'll see you in that one bye-bye you've waited a long time for this because i've avoided talking about these dunder magic methods for a long time in this video we're finally going to uncover what they do now we're able to see what our instance has as methods using the dur method and we told you that these were inherited from our base object class now these underscores are special methods remember how we have things like length for example that allows us to tell the length of an array these are actually implemented using these dunder methods they allow us to use python specific functions on objects created through our class so let me show you what i mean we're going to create a new class and this is going to be a toy class now in here we'll define a toy and initialize it with self then we'll say that it has color and age now we'll say color equals to color so this will be our attributes and age awesome there's our class now let's say we want to create an action figure this action figure will be instantiated with toy let's say color of red and the ages it's brand new so it's zero now if i use something like let's say s t r that comes with this object if i do str or action figure dot underscore underscore s t r like so and we print this we see that we get this it's the exact same thing as us doing sdr action figure this look at that these double underscore dunder methods are special methods that python recognizes for example the dunder str this special method allows us to use action figure like this using the str built-in function as a matter of fact if you go to the python documentation under the special method names section you'll see that we can do basic customizations of these dunder methods and it's a long list of all these dunder methods that we can use now don't go and read every single one of them there are a lot and you're not going to use them that often there's only specific few cases that you're going to use them and the idea is to know how to modify them and how they work underneath the hood so let's go over a few examples for example let's modify what the ssdr does i'm going to define my own str here i'm going to call self and then in here i'm going to return something different i'm going to return let's say an s string that is let's say self dot color if i run this i get red remember how i said not to modify dunder methods well sometimes you're allowed to maybe there are cases special cases where you want your class to behave a certain way just like dictionaries lists tuples and all our objects in python can behave in certain ways how lists were accessed with an index number and a dictionary was accessed with the key those are all implemented using these dunder methods and you see here that because we modified this the sdr now returns red when being called on action figure it doesn't change things other than within action figure if i run this you'll see that it still runs action figure like this because this is a string the str is only modified when we use it on this specific object like so what other neat things can we do well we can change the meaning of the length as well so length i can say self and in here i can just return five now if i print length of action figure and i click run i get five very cool by the way if this underline is getting a little annoying which frankly for me it's getting a little bit annoying i'm going to click on settings here and just remove the code intelligence so it won't tell me when my code is wrong but hopefully we can just debug it ourselves all right so there we go we've just changed the length dunder to return five let's keep experimenting we can also do something like underscore underscore delete and delete well lets us actually use the delete keyword which we actually haven't seen before delete we can just say return deleted you have to go like this and let's just do print here print deleted if i click run i see that i returned deleted now the delete keyword i haven't really taught you because it's not something that you'll see a lot of usually this can cause some funny bugs in our programs that i like to personally avoid but the the delete keyword deletes some sort of variable that we might have had in our program right what else is there let's change this to use something called call and call is an interesting one let's say that with call we're going to return and let's say yes question mark the neat thing about call is that now it gives our toy class some super power we can say action figure and then say well with call we actually can now call the actual object with these brackets so using call i have this special way to call a function which by the way underneath the hood the way we're able to call functions is using this dunder call and if i click run i get yes how cool is that all right one last one because i think you're starting to get the idea of this like i said these are all available in here usually you don't want to overwrite them but you just want to know that you have the power to do so if you choose the next one is called get item so let's do define get item again we're going to use self as the first parameter and then let's say i for index and in here we'll return self dot and let's add an attribute before we add that i'm going to say self dot my dict for my dictionary and then add name equals to yoyo and let's do has pets equal to false now using this i can say my dick and return the item based on the index that we give it so let me show you what i mean if i now do print action figure dot and in here instead of doing the dot we do the square brackets just like we would access perhaps getting a dictionary item we can now using the get item say what properties do we have name so let's say name and if i print this oh forgot to add a comma in here let's try that again and if i scroll down you can see i'm really good at reading errors name error name action figure is not defined because it's action figure not figure that's better look at that my name yo-yo was being able to access using this bracket notation using the get item dunder very very cool so these special magic methods are really interesting because it allows us to do some well some custom modifying of our classes and you can also understand how in python our built-in default types had access and abilities to have all these special syntaxes we now have that power as well let's take a break and do a bit of an exercise i have a fun little exercise for you i want you to create a super list using the class super list now in here i want you to add code that allows us to have just like we have a list in python allow us to access through index through well any way that a regular list allows us to use it but the only difference is that the superlist is going to have a special dunder method let's say that when we do length so when we define dunder dunder length we're going to modify it and we're going to have it return no matter what a thousand now this may look easy because all we want to do is modify the length under here but the question is based on what you learned about inheritance about object oriented programming instead of having to write every single dunder that we need to use on a list how can we easily acquire the power that list already has and then just modify this length dunder so remember super list is going to be a list that we can create we can instantiate like this super list one we're going to call super list and it's going to allow us to do things like length superlist and also access items in the super list or use superlist one dot let's say append and maybe append five and actually get super list one five all right take it away from here give it a go pause the video because i'll give you the answer so let's just implement this we're going to have self in here and we're only going to return let's say a thousand so that when we call superlist one and let's comment this out and i do length here let's print it out i should get a thousand that's good but i want the functionality of this i want to be able to append to my super list so let's run this and see what happens i get an attribute error superlist object has no attribute append let's think about this how can we acquire the powers that lists in python already have well we learned about inheritance right and all we have to do is just simply type list here and now list becomes our parent class of super class so let's give this a go now if i click run all right that seems to work what if we want to access superlist at index well not five at index of zero if i click run i get a thousand well that's because we're not printing anything yet so let's print here and click run check that out we're able to have this super list and we just extended the functionality of list how cool is that now to double check there's a fun little function that we have in python and it's called is sub class and here we say super list and list if i click run i get true because is superlist a subclass of list yep that's true what about this is list a subclass of the base object yep it's true remember everything in python is an object that inherits from the base object class we then inherit some built-in list methods and we're able to use all of that in our super list just by inheriting like this very very cool now for some of you this might have been a simple exercise and you got it right away if you didn't don't worry now you know pretty cool eh i'll see you in the next one bye-bye let's talk about multiple inheritance which you're able to do in python now remember we have our user wizard and archer classes we're trying to build that game right now let's clean up some of this code we won't need the init function anymore we'll just have user here we have wizard that inherits from user and also archer that inherits from user but what happens if we want to create a new character and this character is called a class let's say let's say it's called hybrid borg a weird name i know but here's the thing hybridborg is a special type of character because it has the powers that wizards have which is attack it has the power that archers have which is check arrows and just for fun let's also add run here and we'll just say for run ran really fast all right so we want this hybrid borg to have all of these methods can we do that well we can all we need to do is say wizard and then archer we can give it as many parameters as we want as as multiple inheritances we're inheriting from wizard and archer so that in here let's say i don't do anything and i'll just hit pass if i instantiate let's say hybridborg 1 is going to be hybrid borg class instantiated i can now use all of these things let's check them let's say print hp1 dot run can i do that and again a little spelling error let's make sure it's hybid hybrid borg not hybrid board i hope you're not bored of this video all right i get an error missing two required positional arguments name and power all right because well we have to pass these things in right it accepts these parameters okay so let's say that we want name to be borgi and the power to be 50. if i run this all right it looks like ran really fast run works i was able to inherit from archer what about check arrows if i click run oh i get hybrid borg object has no attribute arrows now why is that because technically we inherited from wizard first then archer and wizard accepts name and power but we never gave the arrows name and arrows so how can we solve that let's try something let's say we added arrows here a hundred would this work that doesn't work does it and this is a tricky thing with multiple inheritance and why some programming languages actually don't even allow multiple inheritance things can get a little tricky because in your head you have to make sure that you understand how these classes are implemented and make sure that we're not overwriting anything in our case we can complicate our code a little bit so what can we do here well in here i can perhaps do something like this i can say define init this receives self it will receive a name a power and also arrows and then finally in here i can say that we're going to call also the archer dot init and that's going to take self and then pass in the name and arrows so that if i run this well let's add the arrows 100 here and i click run there you go arrows is now working now just to check that our attack on the wizard is working as well if we do attack and click run oh boy now our hybrid object has no power so once again in order for us to half power we'll have to copy this and let's say this time wizard init self and then give it power if i click run all right attack works let's go back to check arrow make sure we haven't broken anything if i click that that works as well and then finally what about sign in will sign in work logged in all right oh boy that was a lot and there are a few ways of actually solving this problem what i wanted to show you though is that when you do multiple inheritance things can get complicated and although we walk through it step by step imagine if there was a coder that came along on your team at work and try to understand this code we've added quite a bit of logic here and things are getting more and more complicated and it's hard to keep track of everything in your head and this is why multiple inheritance is one of those things where it's really really powerful but with great power comes great responsibility because we're creating more and more complexity again part of the reason that some programming languages don't actually allow you to do multiple inheritance and by the way i'm going to confuse you even more in the next video we're going to talk about something called mro and it's going to be another great example of why you want to be cautious with multiple inheritances i'll see you in that one bye-bye let's talk about something that sounds quite complicated it's called m-r-o or method resolution order what does it mean well i have an example here for you let's say we have a class of a class of b that inherits from class of a does absolutely nothing and then we also have class c that inherits again from a and then finally a class d then inherits from b and c so we have two classes that do absolutely nothing and then a class a and class c that have the same class object attribute and i've actually drawn out how this relationship looks like you see that d has multiple inheritance from b and c and b and c inherit from a and mro or method resolution order is a rule that python follows to determine when you run a method which one to run when you have such complicated inheritance structure mro is a rule that says hey do this do this and then do that and that's the method that you should run let me show you what i mean let's say i wanted to do print d dot num what do you think will happen here let me move this out of the way or comment this out if i run this can you guess what's going to happen if i click run i get one is that what you expected let's look through this d inherits from b and c and then those inherit from a so we get one because the mro the method resolution order is that it doesn't go d b a instead it goes d b c a let's think about this a little bit more and my row is simply saying what's first in line if things are common between classes methods or variables or attributes what should i pick and there's actually a good way for us to check this if i do mro and then run it like this if i click run look at that this is the order or the mro of this class it says hey i'm going to check d first if you call let's say d dot name or d dot num i'm going to check main dot d first so i'm going to check this class then i'm going to check main dot b so i'm going to check b and then i'm going to check c and then i'm going to check a and then finally i'm going to check the base class object again we've seen that before it's the base class that all objects in python inherit from so that's the order that it checks for num if we pass all of these and i click run i'll get an error d has no attribute num because it went through all this path even checked the base object and never found num if i did something like str if i click run this works because it goes all the way through the inheritance chain and then gets to the base object and the base object actually has this so it doesn't error out and yep you can use the dunder string now i found a great example here to show you why inheritances can be confusing and why things like mro you might want to avoid or at least be conscious of so let's copy this code and let's just remove all of this and we're going to play a little game now this syntax looks like this so this is the inheritance model of what we just created looks uh pretty confusing doesn't it so if we do m here and we check the mro or method resolution order of m what do you think the order is going to be pause the video here and try to guess what the order will be ready let's do m dot mro and by the way another way of doing this is to use the donder mro and let's print this all right let's check this so the first thing we have is m all right we check him and then we check b we check b all right and then we check a so we check a here and then we check x x over here then y then z then the class object is that why you guessed let's look at the code why this order well the order is because of the way that we're passing in the parameters you see b is passed before a and c so that means the order of mro is going to be b then a but hold on after b and a what was that well after b and a we have class x why did x come before z so instead of going to z let's make this a little bit bigger instead of going to what we would have thought would be z it goes to x then y then z then the object this is because of the algorithm that they use for doing mro which is called depth first search now this is beyond the scope of the course but as you can see it's quite a bit confusing and as a matter of fact python actually changed the mro rules from what we have previously in younger versions of python so this is another one of those things that got updated but the reason i'm showing you this is because you're never going to get tested on this stuff if you're writing code where the inheritance looks like this i argue that you're writing bad code because this is overly complicated we haven't even written any code actually inside of these classes and it's already confusing so mro is there as a way to define what order you're going to inherit it and you can always use the mro function or dunder to check this but the reason i brought it here is not just trying to confuse you the reason is that it exists however you should not structure your code in this way this doesn't mean that this doesn't happen in the wild yes it does but at least you have a way of checking and maybe debugging your code when you see a problem like this i'll leave a resource for you about mro if you're really curious and you really want to understand how this algorithm works and how this order is actually determined but the key takeaway is that this is the way that python works to determine hey when you call a method or an attribute this is how i'm going to look up the hierarchy of inheritances all right if your brain hurts don't worry so does mine take a break and i'll see you in the next video bye-bye you
Info
Channel: ComputerScience Geek
Views: 7,645
Rating: 4.9499998 out of 5
Keywords: Complete Python Developer 2021 Zero to Mastery Playlist, Python Basics in 2 hours, What Is OOP, Creating Our Own Objects, Attributes and Methods, __init__, @classmethod and @staticmethod, Reviewing What We Know So Far, Encapsulation, Abstraction, Private vs Public Variables, Inheritance, Polymorphism, super(), Object Introspection, Dunder Methods, Exercise Extending List, Multiple Inheritance, MRO - Method Resolution Order
Id: vgeTzWo0pXg
Channel Id: undefined
Length: 123min 4sec (7384 seconds)
Published: Fri Jun 04 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.