Object Oriented Programming (OOP) In Python - Beginner Crash Course

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hey guys in this tutorial i'm gonna teach you all the things you need to know about object oriented programming in python you don't need to have any other previous knowledge about classes and objects to follow me here so we start at zero and then step by step improve our knowledge until we have covered all the important concepts and here is the outline so i divided this course into five sections first we start with a little motivation so why do we need classes and then i show you how we can create classes then we talk about the difference between classes and instances then i show you how we can use functions inside classes then we talk about inheritance so how we create a base class and then a child class that derives from this base class and this is probably the most complex topic but also the most interesting one then we talk about encapsulation so this is a fancy word that i'll explain later and then i also show you how we use properties so this goes hand in hand with the encapsulation principle and shows a pythonic way how to use scatters and setters and during all those sections we also talk about the four principles of object-oriented programming so this is a typical interview question for beginners and everyone should be able to explain them so right now i only tell you those four principles so we have inheritance polymorphism encapsulation and abstraction but i will not tell you the definition right now so instead we will learn about them while i'll explain the concepts in the code later and then at the end hopefully you have a good understanding of what all those principles mean so i hope that you stay with me until the end and now before we start just a quick note if you find this tutorial helpful then please hit the like button and consider subscribing to the channel i provide a lot of free tutorials here and this will help me to keep going so let's jump to my editor and let's start with the motivation so why do we need classes so in python we have primitive data structures like integers and strings or even lists but they are designed to represent only simple pieces of information so what happens if we have a more complex type that we want to represent so in this example let's use a software engineer object so we want to represent a software engineer so what we could do here is we could use a list so let's create a software engineer one and then we use a list so let's define what we want to have here so we um give him a position so this is his title software engineer then he should have a name he should have an age and then the level and the salary so we could use a list here so let's say the position is a software engineer then the name let's say this is max and then he is 20 and he is a junior um developer and let's give him a salary of let's say 5 000. so this is one way we can do this so and now when we use multiple then let's create a second one so our software engineer two and let's say this is lisa she is 25 and she is already a senior and her salary let's say this is 7 000 so you might already see that when we create more of those objects then this can become cumbersome and also error prone so for example what will happen if for example in this list the name is missing or what happens if this is not even a software engineer but something else for example a designer and then what also will happen when our software engineer should do things so let's say later he should write some code so then only our software engineer should do this and not um if this is something else so if this is a designer or something so you might already see that a list is not the perfect data structure to represent such a complex object and this is the reason why we have classes so classes are used for more complex data structures and they contain functions that then describe the behavior of our class so a class is basically a blueprint how something should be defined and the way we create a class in python is with the keyword class and then we give it a name and by convention we start here with a capital letter so let's say this is a class called software engineer and for now i only say pass so we don't do anything here and now this is already a valid class in python so let's say here this is a class and then we can create an instance of this class so here when we create a instance we say our software engineer 1 equals and then a the name of this class and then parentheses so now we have an instance of this class so now what is the difference again so a class is only a blueprint of this data structure so here we are going to describe how this data structure looks so for example it says it has a name and an age but we don't put any concrete information in here only then later when we create our instance then we say the name is max or lisa and he's 20 years old or 25 so this is the difference between instance and class and now let's have a look at how we can implement our class so right now it's not doing anything but if i run the code then um this works so it won't crash so now let's um say our class should have all those attributes that i listed here and we will do this with the init functions so we define it with our with our function keywords def and then double underscores and then init and then again double underscores and then as a first argument it always gets self so this is just something that we need to know and i will talk about this in a few moments so this is a special method that we can use to initialize our object and here we can put in any parameters that we want so let's say here we want to have the name the h the level and the salary and in here the only thing we do for now is um we want to store them inside this class so what we do is we say self dot name equals name and then we do this for all those parameters so self.h equals h self dot level equals level and self.salary equals salary now this might look like it's redundant but this is actually important so there is a difference so all of those parameters are the parameters that we pass in from the outside and all those parameters that are that have self here that can be used inside this class and these have a special name so they are called instance attributes and now if we run this code then this will actually crash so we see we get a type error missing four required positional arguments so now since we created this init function when we then create a instance then we also have to use those parameters so let's use the same four parameters that we have here in this same order we have the name the age the level and the salary and now if we run this then this works and now we can access those instance attributes so now for example i can print and then s e one software engineer one dot name and that's also prints dot h and then we see that this is working so we pass in max and 20 and also those parameters and then inside here they are stored and then we can access them like so and then when we do this um it is referring to those instance attributes self.name and self.h so again not to these ones these are only the parameters that we pass in from the outside here all right so by now we already know how we can have a class and a instance and then instance attributes so what happens if we um don't write a attribute in here but instead we say it's um here so let's say our software engineer has an alias and here let's say his alias is he is a keyboard magician and now this is called a class attribute so here inside our init function we have the instance attributes and then here we have a class attribute and now the difference is that a instance attribute only belongs to one object that we created here and not to the whole class for example we cannot say software engineer dot name so if we do this then this crashes because the name is only tied to a specific instance but on the other hand a class attribute um is um the same for every instance so it can also be used on the class itself so we could say um print se1 dot alias so this works but we can also say print and then software engineer dot alias this also works so again the instance attributes are only tied to one instance and we cannot use it on the whole class but on the other hand a class attribute that is defined here can be used on the class itself because it's the same attribute for each instance so let's say we create another instance of the software engineer so this time we take these parameters so we have lisa and 25 a senior and her salary and this is our software engineer 2 and so here again if we print se2 dot alias then this is also a keyboard magician so we can simply say and we can call this on the class software engineer dot alias all right so this is all for section one so let's do a quick recap what we learned here so we learned how we can create a class and we should know that a class is used as a blueprint so here we only describe what we want to have in our class so the name the age and the level but we don't store um complex or the actual attributes the actual name and the age so the class is only the blueprints and then we know how we create a instance where we have the concrete um the concrete parameters and the instance sometimes it's also called just an object so here we have an instance and here we have another instance so now you should know the difference between a class versus an instance we also know that we can define instance attributes and they are defined in the double underscore init function and here we need self and then we also see how we can use a class attributes and what's the difference between a class attribute and an instance attribute all right so let's have a look at how we use functions in our classes and this should also further clarify why a class is a better structure than a list like here to represent a software engineer so let's start with a little motivation why we should use functions in classes so we could of course just define a global function here and pass in a software engineer so let's say our software engineer should do something so in this example he should write some code so we define a function code and then here we simply print and let's then say we pass in this list so we want to print the name so if we want to access the name from this list then we get it with the index um one this is the name so let's simply print this name is writing code dot dot and now we can call this function so we can say code and then software engineer one then this is working so it tells us max is writing codes if i pass in number software engineer 2 then it says lisa's writing code so this works but now let's say we have a third object and this is a designer so here we use a list and the position is a designer and then the name is a let's say this is philip and then we could also pass this designer to the code function so if we say d1 then this is also telling us that philip is writing code but actually this shouldn't be possible because yeah i know maybe some designers also know how to code but let's say in our example our designer shouldn't be able to code then this shouldn't be possible but if we write it like this then we can pass anything into this function and for anything we can try to write some code so wouldn't it be better if we tie this function to our class software engineer and this is exactly what we're going to do so let's delete this and then let's grab this function and then here inside of our class we define this function and now what we don't need is we don't need this software engineer object but the same like here we need to have self so this is something that we just have to remember for every instance method and yeah by the way so this is called a instance method we have to write this self here and then we can access all of those instance attributes that we stored here so here we can say we can access the name by saying self dot name is writing code so this is how we define a instance method and then when we have an instance here then this instance can do something so this can execute this function so now we can call se1 dot code and this is working so now it says max is writing code and we can also say se2 dot code and then we also get lisa is writing code so this is how we use an instance method and please also note that we have this one parameter self here but we don't pass this into this function when we execute it so this is automatically included for us so the same in the init function here we have self um as first parameter but then when we create it we start with the name so remember that for each instance method when we define the function then we have to use self but later when we call the functions we don't use the self anymore so this self parameter refers to the instance um itself so to this op specific object and then we can access all those object specific attributes self.name self.h etc so now we have our first instance method so let's create another one so let's say define another more specific code function so let's call this code in language and then remember self as first parameter and then let's say we also give it a parameter language and then we say here self.print self.name is writing code in and then here let's use this language so we see we can also use parameters for a instance method so now we can say for example se1 and then code in language and let's say python and now if we run this we see we get max's writing code in python and for example we can also say se2 code in language and let's say c plus plus then we see lisa is writing code in c plus plus so we see we can use parameters and we can also return things from these functions so let's create another function information with self and here we want to create a variable information equals and let's use an f string and then we say name equals and then we can access self.net and let's also say h equals and then let's access again our self.h and let's say we also want to print the so level equals and then self dot level so this is the information and then we simply return the information here and then here we can print and then call se1 dot information as a function so now if we run this then we get the information here okay so now we know how we create instance methods and now let's talk about some special methods and these are the double underscore or d under methods so they start with a leading double underscore and a trailing double underscore like the init function this is also a d under method so these are special methods that are already provided for us in python so every object already has this so if we don't um declare them then it still has some implementation of this these functions but then if we write our own function then it's using uh this function so let me show you two more examples of the under methods and one is called the string or sdr method and this also gets self of course and then this will be executed whenever our object is converted to a string so like here um we can say we want to have this as a representation for the string so we want to print the information so we create this information and here we also have to return this so we do have to do this here inside this mess method so now let's comment this out for now and let's print only our software engineer object and see what's happening so then we see we get this so we get our class name objects at and then this is a memory location so this is working it doesn't crash so it prints some information and this might even be useful but in our case it doesn't tell us a lot of things about our object so let's say instead we want to have this information when we print our object so then we can define this string method with a double leading and trailing underscores and we return them and then we don't need this function anymore so we can get rid of the information function and now if we run this and print our object then it's printing exactly this so this is the string representation and that's why it's printing the name the age and the level so now if we print se2 then it's printing name lisa h25 level senior so this is um one special d under method so let's write this here the under method and there are a bunch of more and for this i recommend to check out the official documentation and right now i want to show you one more and this is the equal function or equal method and this gets self and it also gets another parameter which is called other and here we compare two objects so again let's test this without um writing this so then as i told you this is already provided for us but with the default implementation right now and by default it is comparing the memory address so now let's say we have another software engineer with exactly the same parameters so se3 and now if we print let's print se2 equals equals se3 then if we run this then we see this is false even though they look the same here and this is false because it's comparing the memory address and this is different so now let's um implement this define equal equal function and now let's say our um [Music] object is the same let's say in our case it's the same if the name is the same and the age is the same so we could of course also check those or other things whatever we want but in this example let's say we want to return and then we say self dot name equals equals other dot name and self dot h equals equals other dot h if both are the same then this returns true and otherwise false so now if we run this and print if this is the same then we see we get true because the name is the same and the h is the same now let's say this h is 27 then it will be false again so these are two special the under methods that i wanted to show you and until now we have learned how we can use those instance method with the self parameter so what happens if we have a method and let's say we forget the self method or this might even be intentional so let's say we create a function and let's call this entry salary and this is calculated based on the h so let's say if h is smaller than 25 we return the salary is 5 000 and if the h is smaller than 30 then we return let's say 7000 and otherwise if it's even older then let's say we return 9000 so now we don't use the self parameter so now let's see what happens if we call this on an instance so if we say se1 dot entry salary and this needs an age so let's give him the age 24 and now let's run this and now this will crash so this produces a type error entry salary takes one positional argument but two were given so this might be confusing for a beginner so what the heck does that mean two were given so it seems like two parameters were given even if there's only one and if you followed me carefully then you should already know the answer because as i said previously the self argument is automatically passed for us to this object so since we use an instance here it tries to put in self in here and then it thinks that it has two arguments but now our function only uses one so now if we use self here again then um this works so of course we don't use self here so if you write it like this then it works again so but let's say um we don't want this in this case so this is actually intentional so we want to be able to compute an entry salary if we give it an h but this doesn't have to be tied to a specific instance so this is not possible in this case however if we call it on the class then we can say software engineer dot entry salary and let's say 20 let's say 27 and we print this to see the result then it's working so it returns 7 000 so this is similar to the instance attributes and the class attributes so here um we can only use this function on the class but not on an instance because we didn't use the self parameter so yeah this works but this will crash so yeah that's the difference and now i want to say that in practice you will almost never see it like this so what you will see instead is with a decorator and then we use this decorator static method so if you don't know what a dagger rater is then i have a whole tutorial about this as well so i will put the link in the description and you can check that out so now if we have that then it's still doing the same so it works on the whole class so if we run this then it's still working and now if we run it on our instance so let's print this as well then this time it's not crashing so this is working but um as i said this is not tied to a specific instance so we cannot access those instance attributes so if we want to compare self.h for example then this will produce an error self is not defined so yeah in practice when you see a method in a class that should not be tied to a specific instance then most of the time you see it with this decorator static method so then you can apply it on both a instance or the whole class but you cannot access the self attributes in here so yeah this was section two and again let's do a quick recap what we learned here so we learned how we can create those instances methods and we know that we should use the self parameter then we learned that our methods can take arguments and they can return values then we learned about the or let's write this correctly can take arguments and can return values then we learned about the specialty under so let's put this in quotation marks the under for double underscore methods so d under method and i showed you the string and the equal method and we learned how we can use the static method so with a decorator and use this on the whole class alright so let's continue and now let's talk about inheritance so that's probably the most interesting section in this course so inheritance is the process by which one class takes on the attributes and methods of another class so this newly formed class is then called a child class and the other one is called the parent class so let's have a look at what this means and how we do this in practice so let's say we still have our software engineer class so for now let's say only pass and let's say we also have another um position so the the signer and for now we also only say pass and now let's say both are um positions in a company so both of them are employees so let's use a second class and this is a employee so this class is more general so let's say our employee should have a name and an age and also the software engineer should have a name and an age and also the designer should have a name and an age but then later only our software engineer has this title junior or senior developer and not the designer so for this we can use this inheritance and we say that our employee is the base class or the parent class and this is a child class that inherits from this class and we do this with this syntax so we use parentheses and then put in the base class and we do the same for our designer so our designer also inherits from employee so now both of these classes are also employees and what this then means is so first of all it inherits all of the attributes and functions from the employee so this will become clearer in a few moments when we do the actual implementation so we can inherit from this we can also extend this and we can override this so also this will become clearer in a few moments so first of all let's um talk about inheritance so let's say our employee now should store some attributes so for this as you should know we implement the init function with self and it gets the name and the age for now only so this must be define our function of course and then in here we simply store them so we say self.name and self dot h so equals h and now we have this so we only defined the init function in our employee class but we didn't do anything in the software engineer class but still our software engineer now has the name and the age so let's create a instance s e equals software engineer so let's try to use it like this because we don't have any init function in here so but now it gives us a type error in it missing two required positional arguments name and age so even though uh we didn't use an init function in here it inherits the init function from his parent class from the employee so we must use this one and this takes a name and an age so we must use a name max and an h and now if we run is run it then it's working and then we can also access those attributes so we can print se dot name and se dot h so we see that this is working and now let's do the same for a designer so let's create a designer and this must get a name and an h so let's use um what did we use before for our designer let's say this is philip and he is 27 and now also for our designer we can print the name and the age so designer.name and designer.h so this is working and now we are already see how we can inherit the attributes that we define only in the base class and the same is true for instance method so let's define a function in our um base class and let's call this work and then here we simply print and then an f string and then let's first access the name self.name and then let's write is working dot dot so now um both our software engineer and our designer can work so we can call se dot work and we can call our designer d dot work and run this and then so let's remove this print statement again and now if we run it we see max is working and philip is working so it inherits all the attributes and all the functions here all right so now let's have a look at how so now we already covered the inheritance so now let's continue and let's talk about extending and overriding the functionality so of course our software engineer can also have its own methods and attributes so first let's start with its own init function so for this let's say he also has a name and an h of course and he should also get the level and the salary so what we do then is since we already have this function um in the base function we don't do the same code in here self.name equals name and self.h equals h instead we call the initializer of its parent class and we can do this with the keyword super so this is referring to its parent class so to this one employee and then we call employee dot init and this gets the name and the h so now our parent class is initialized correctly and now we want to store the other parameters that are specific just for our software engineer so we say self dot level equals level and self dot salary equals salary and now by the way i realized that each employee should have a salary so i think this is should be better up here so now eve also our employee gets a salary and then we have to pass it to our base initializer and let's change the order here salary and then the level and we only store the level in our software engineer class so now um since we changed that of course we also have to change this initializer so also the designer now needs a salary so let's say seven thousand and our software engineer also gets a salary so let's say six thousand and as level let's say junior so now this still works so if we run the code we still see max is working and philip is working and now for our software engineer we can access its level and print this so now if you print the level then we see this is junior but this level attribute now only works for our software engineer and not for a general employee and also not for the designer so here we see how we extend the functionality and we also already saw how we override functionality so since we are using this init function here we are overriding the init function of its parent class so now we must always use this initializer and then call the super initializer in here so this is also something that we must remember if we use um if we override the initializer and the initializer of the parent class is doing something else or something different or other then we must also call this super initializer here so so that our object is then initialized correctly so now everything is working it has the name the age the salary and the level so this is how we override it so now let's extend our child classes some more and give them its own functionality so let's define a function that is only specific to a software engineer so let's call this function debug and it gets self and then here inside here we print self.name is debugging so now our software engineer can debug and in our designer class let's extend this class and let's say our designer can draw and it also gets self and then we print self.name is drawing so now our software engineer can debug so now if we run this then we see max is debugging and our designer can draw so now this is working as well so now we get philip is drawing and we don't have to double print this here so this should still print the output yes and now for example to make this more clear our software engineer cannot draw so if we try to draw with our software engineer then it gives us this attribute error software engineer object has no attribute draw so these functions then are only specific to the child class so this is how we extend the functionality of the base class and now let's do one more example how we override the function so we already saw how to override the init function and now our base class also has the work function so let's also override this one so we define the same function in this in the child class so for the software engineer and also for the designer and with this if we use the same function with the same name again then we override this and if we use a new function then we extend this so in our employee class we just print um self.name is working in our software engineer class let's say self dot name is coding and in our designer class let's say self.name is the signing and now if we save this and call softwareengineer.work and the signer.work then we see that we get max is coding and philip is designing so we have overwritten this function and now since we created a software engineer it's taken the overwritten function from this class and not from the parent class so yeah so now we see how we can inherit extend and override functionality so with this we can get rid of redundant code and we also get code for free so we don't have to implement for example the init function in the child class but we still can access designer dot h and designer.name and also for all of them we can access the work function if we don't implement them in here so if we do it like this and call this software engineer dot work then it's still working so yeah and i hope that it's starting to become clear that this is a very powerful concept that you should know about so yeah now we learned about inheritance and now let's talk about one other principle of the object-oriented programming and this is called polymorphism and what this means so this is greek and means many shapes and this is closely related to inheritance so we can write codes that works on the super class but it will also work with any subclass type as well so simply put polymorphism gives us a way to use a class exactly like its parent but still each child class keeps its own methods as they are so let me show you an example so let's say we have a collection of employees and for now we don't care which type of employee this is so we have a employees list and this is a list and then in here we for example we create a software engineer then let's create another software engineer so this is lisa she is let's say 30 and her salary 9000 and she is a senior and then we also have this designer in here so now we have this collection of employees and we want to treat them just as an employee so we don't care what's the actual child class right now so let's say we are somewhere else in our code so let me scroll down so that we don't see it anymore so let's say we are in the for example we are in the hr department and we want to motivate our employees so we write a function define motivate employees and this gets a list of employees but here we don't know what type of employees they are we simply want to iterate here and say for employee in employees and then we can call employee dot work so this will work on all employees but then we get the specific um implementation of the child class so it can take different shapes so this is what polymorphism means so now let's call this function motivate employees and we pass in this list that we created then it iterates over each one and prints and that the work function so um let me comment this out and this out so these are the only um work calls that we should see and now let's run this and then we see this is working and we get max's coding lisa is coding and philip is designing so yeah this is the concept of polymorphism and now let's do a quick recap again of our third section so what we learned here is we learned about inheritance and um that we can use it with a child class and this inherits from a base class with this syntax then we learn that we can inherit the attributes and functions here we can also extend attributes and functions and we can override functionality and we learned about the super um init function so if we overwrite the init in a child class then we must be careful and should remember to call the super class of the base class at the super method of the base class and we learned about the concept of poly more fism all right so now let's continue with section four and now let's talk about two more concepts of object-oriented programming and this is encapsulation and abstraction so let's first talk about encapsulation so encapsulation is the mechanism of hiding of data implementation so this means that instance variables are kept private and there's only one accessor method from the outside with which we can access or change these instance variables so with this we restrict the access to public methods so-called getter and setter methods and we can also do the same for methods so instance methods can be kept private so that they should only be used internally and not from the outside so let's write some code so that this will become clearer so let's define a class again for our software engineer and here we again define the init function with double underscores and self and now um again let's say it gets the name and the age and then we say self.name equals name and self.h equals h so right now we don't want to set the salary so let's say the salary should be private so no one should see this except later maybe the hr department can access the salary and also set the salary so for now let's create an internal variable an internal attribute and this should be private so by convention we use one underscore here and then the name so self underscore salary and in the beginning this should be none and then let's also use another private attribute and let's call this the number of bugs solved so this will be useful later for an internal function and in the beginning this is so [Music] right now these can be accessed from the outside but these should be kept private so if we now let's create a object again a instance s e equals software engineer and the name is max and the h is let's say 25 so we can print s e dot h and we can print s e dot name so let's run this and now um we shouldn't access the salary from the outside so technically in python this is not completely private so for example we can access the self dot salary so if we initialize this with 5 000 and save this and run this comma then technically this is working so we can access this from the outside but we shouldn't so for each attribute or function with an underscore this should be kept internal so if we want to make it really private then we could use a double leading underscore and now if we try to access this then this will not work so this will raise an attribute error because from the outside it doesn't see this variable here because we use this private syntax but yeah in practice you almost never see this but you see one leading underscore in practice a lot so yeah so as i said technically you can access this but you shouldn't access this from the outside and yeah so right now we have public variables or attributes and private attributes and now these are only used internal but now let's say our hr department needs a way to access those variables so we can say we define a public function get salary and here we simply return this so we return self dot underscore salary so again here we are inside of this class so this means we should be able to access this and then also from the outside our hr department should be able to set the salary so we define a function set salary and this gets self and then it gets a value and now here we set this so we say self dot self.salary equals value and now let's change this to none in the beginning and then from the outside what we do here is we say s e dot set salary let's say 6 000 and then s e dot get salary and print this then this should print six thousand and here i made a beginner mistake so i said we should always remember to put in self and now i forgot it myself so yeah put in self and run this again so yeah so now it's working so we see we get 6 000 here so now we should be able to access and modify it from the outside but these two functions so-called getters and setters this should be the only way from the outside to access this internal self.underscore salary attribute so why is this useful why should we apply such a concept with this encapsulation and this pry with attribute so for example what we could do here is when we set the salary we could do some more stuff for example we can check the value if this is actually a valid salary we can also enforce some constraints so we can be funny here and say if the value first let's check it if it's smaller than 1000 then let's say no this shouldn't be possible then let's still say self dot salary equals 1000 and if we accidentally put in more here if our value is greater than 20 000 then let's also restrict it let's say this shouldn't be possible then this should be um 20 000 and not more so we can do checks we can enforce constraints or we can of course do other stuff for example we can check if the bank the bank information is still valid so yeah that's why these scatter and setter can be useful and now let's also show you how we can apply this concept for a private function so let's give it first let's give our um software engineer the code function first again with self and then in here what we want to do we want to increase the number of bugs solved so we say self dot num bucks solved plus equals one so now it should be clear that there is no need to access this variable from the outside the only place where this is relevant is when we do work with our software engineer so when he is coding then he is also solving bugs so this is the only place where this will be increased and so yeah so this is one um more internal thing and now let's say when we set the salary we only want to set a base salary from the hr department because the hr department is not so familiar with the work the software engineer is doing so they are only setting a base value of the salary and then inside here we calculate this so based on how productive our software engineer was so for this let's write a internal function and now this also gets a leading underscore and let's call this define underscore calculate salary and this gets self and this should get the base value here and then we check if self dot underscore num buck solved is smaller than 10 then we simply return the base value if self dot num back solved is smaller than 100 then we apply a factor so we return base value times 2 so he gets double the salary and otherwise if he even solved more than a hundred bucks then we say we return base value times three and now in here um so let's get rid of those constraints so we don't want them right now so let's say our self.salary equals dot underscore calculate base calculate salary with the base value so now this is how we do this and now again we only want to do this internally there is no way there's no need from the outsides to call this the only thing we want to call from the outside is then set salary and get salary so now let's say we have a software engineer and let's say he is being very productive so let's say for i in range and then let's say one let's only use 70 right now and then we call se dot code so he is coding 70 times this means that our number of bucks solved um should be 70 so [Music] for now we can do a quick check so we can say print s e dot and as i said we can access those um private parameters this is just for demonstration that this works so yeah but we shouldn't do this but we see this is 70 and now we set a base salary and now if we print the base salary so then it should be in this if case and it should apply the factor to so now if we get this then we should get 12 000 actually so let's run this and see if this is working and we see we have 12 000 here so our code is working fine and yeah so this was all in section four so now we talked about encapsulation so the mechanism of hiding data implementation and restricting the access so we see how we can use public getter and setter functions and then they access a private attribute inside and we also can use private functions and they are all um defined with a leading underscore so this is the concept of encapsulation and now only one principle is missing and this is the principle of abstraction and this can be thought of as a natural extension of encapsulation so applying abstraction means that that each object should only expose a high level mechanism for using it so this mechanism should hide internal implementation detox details it should only reveal the operations relevant for the other objects so again if we have a look at this set salary function then this is applying the abstraction principle so we only from the outside the hr department for example should only be able to set the salary like this but they don't care about this internal implementation calculate salary with this factor alignment so yeah so this is abstraction and now we already covered all the four principles so i will show them again at the end and now let's talk about one more thing and this is about properties and um the setters and getters so instead of using these function get salary and set salary there is a more pythonic way to do this and now let me show you how we do this so first of all let me clean this code so let's get rid of all the other things so that the demonstration will get clearer so let's remove this and this and this and this is only the value so we have this and then we remove this one and now we create a software engineer and as as before we are able to set the salary and get the salary so let's run this and we see this is working so yeah so as i said there is a more pythonic way and this is with a so-called property so for the getter um we give it the name of the property that we want so we use the salary name without the underscore and then we use a decorator and use the property decorator so again if you don't know how decorators work then check out my tutorial and now instead of this set salary what we do here is we again give it the same name here and then we also use a decorator and then again the same name salary and then dot setter so now we have a getter and a setter and now what we can do here is we can instead of calling this function we can simply say se.salary equals 6 000 and we get the salary by accessing the property without these parentheses so now if we run this then it's still working and this is a more pythonic way of doing it than using the get and the set function and there is also one more decorator and this is the salary at at celery deleter and what we do here is we delete self dot salary and this doesn't get a value so now we can um call delete s e dot celery and now when we try to print this again then we should get an error so now we see software engineer object has no attribute salary because we deleted it and if we remove this and run this then it's working so yeah in practice i don't think that you see this one very often but you should be aware that this is also available and again why do we do this this way instead of just using self.salary here and then [Music] setting and accessing it like this so again this should apply this encapsulation principle that this should be the only way from the outsides to access this and for example here again we can do some checks or constraints or internal calculations so again let's do a recap so we talked about the encapsulation principle and we talked about the abstraction principle then we talked about public and private methods and attributes and for example we learned that we use a underscore here for a function and also for a attribute a leading underscore and we learned how to use scatter and setter methods which are the only way to access them from the outside and we also learned a more pythonic way for the getter we can use a property and for the setter we use this at decorator and then the name let's say only x dot setter like we are doing here so yeah this is everything i wanted to cover here so now let's go back to our four principles of object oriented programming so i hope that they are clearer now for you so again let's go over the definitions one more time so what is inheritance inheritance is the process by which one class takes on the attributes and methods of another and newly formed classes are called child classes and the classes the child classes are derived from are the parent classes child classes inherit all of the parents attributes and methods but can also extend and override the attributes and methods that are then unique to themselves then we have polymorphism which which means many shapes so this means we can write a code that works well on the super class and it will also work with any subclass type as well so this gives us a way to use a class exactly like its parent but each child class keeps its own methods as they are then we have encapsulation encapsulation is the mechanism of hiding of data implementation so instance variables are kept private and accessor methods are made public to achieve this so with this we restrict the access to those public getter and setter methods and the same for instance methods they can also be kept private and then we have abstractions so this can be thought of as a natural extension of encapsulation and applying abstraction means that each object should only expose a high level mechanism for it this mechanism should hide internal implementation details it should only reveal operations relevant for the other objects so yeah we covered a lot today and these are all the essential topics that you should know about object oriented programming there are still a couple of more concepts more advanced concepts in python available but i think for now this should be enough and i hope that you enjoyed this tutorial and then i hope to see you in the next video bye
Info
Channel: Python Engineer
Views: 70,197
Rating: 4.9614959 out of 5
Keywords: Python, Programming, Tutorial, OOP, Object Orienter Programming, Class, Instance, Objects, Inheritance, Encapsulation, Polymorphism, derive, super, crash course, OOP Principles, staticmethod, getter, setter, instance attributes
Id: -pEs-Bss8Wc
Channel Id: undefined
Length: 80min 54sec (4854 seconds)
Published: Sun Nov 08 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.