Afrikaans
Akan
Albanian
Amharic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranรฎ)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Persian
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
it's important for software developers
to understand object-oriented
programming
in this course jim from gym-shaped
coding will teach you all about
object-oriented programming in python
object-oriented programming it could be
what is holding you back from being a
great python developer and as well as
landing your first job as a software
engineer
welcome everyone to python
object-oriented programming course now
if you struggle to understand the
concepts of object-oriented programming
in the past then you are totally fine
and you are in good hands because in
this course i'm going to make sure that
this will be the last tutorial that you
will ever watch about classes and the
complex concepts that comes with object
oriented programming and we are going to
do this by developing a real python
application that is going to be very
cool to write and we will add to its
complexity step by step and throughout
the way we will understand everything
that we need to know about
object-oriented programming now there
are going to be some requirements to
this course i do expect from everybody
to know at least about functions
variables if statements and as well as
for loops and if you know those things
from other programming languages then
this is also fine so with that being
said let's get started now to explain
why you should write object oriented
programs i will explain the concepts
based on a store management system that
we will start developing together so
starting to think about how to take our
first steps with such a program we could
first think about tracking after the
items that we have right now in our
store so one way we could get started we
could create those four variables to
start tracking after our items so as you
can see we have our first variable item
one equals to phone and then we have
three more variables that are
intentionally starting with the prefix
of item one so that we could describe
that those four variables are related to
each other by following the correct
naming conventions now you might think
that those four variables are related to
each other only because it uses the same
prefix of item one for python those are
just four variables with different data
types so if we were to print the type
for each of those four variables now we
would receive their types with no
surprises right we will receive string
and integer for price quantity and price
total now i want to focus on those
specific outputs right now because as
you can see for each of the types we
also see the keyword of class now this
means that those data types are actually
instances of strings or integers so in
python programming language each data
type is an object that has been
instantiated earlier by some class and
for the item1 variable that has been
instantiated from a string type of class
and for the price quantity and price
total those have been instantiated from
a class that is named int meaning
integer so it could have been nicer if
we could tell python that we want to
create a data type of our own it will
allow us to write a code that we can
reuse in the future easily if needed now
each instance could have attributes to
describe related information about it
and we can think about at least some
good candidates for attributes we could
have for our item data type like its
name
price or quantity all right so let's go
ahead and start creating our first class
so i will clean everything from here and
we'll go ahead with it so it is going to
be divided into two parts the first one
will be the creation of the class and
the second one will be the part that i
will instantiate some objects of this
class now when i say creating an
instance or creating an object basically
i mean to the same thing so you might
hear me saying one of those all right so
let's go ahead and say class and then
this needs to be followed by the name of
the class that you want to create so we
would like to give it the name of item
and then inside of this class in the
future we are going to write some code
that will be very beneficial and very
useful for us so we won't repeat
ourselves every time that we like to
take similar actions but for now
temporarily i'm going to say here pass
so we will not receive any errors inside
this class definition all right so now
that we have created our class then we
are allowed to create some instances of
this class so let's go ahead and say
item one is equal to item and that
action is equivalent to creating an
instance of a class just like if you
were to create a random string
then you will say something like the
following this is equivalent to this one
as well so it is very important to
understand how classes are working in
python so i will delete this line
because this was just for an example and
now i said that we are allowed to assign
some attributes to instances of a class
so let's go ahead and start creating
attributes and that will be achievable
by using the dot sign right after the
instance of a class and here you can say
that you want to give it an attribute
like a name that will be equal to phone
and item1.price could be equal to
100 and item one dot quantity could be
equal to
five for example now in that stage you
might ask yourself what is the
difference between the random variables
that we have created to those four lines
well here we actually have a
relationship between those four lines
because each one of the attributes are
assigned to one instance of the class
and i could preview this by going ahead
and try to print the types of item one
now and as well as the types of the
attributes of
name price and quantity now with name
price and quantity we are not going to
have any surprises because we assigned
string type attributes to the item
object but if we were to print that then
check out the result if i was to run
this program so you can see that now we
have a data type of item here and that
is the big difference between what we
have seen previously to this thing that
we have just created so now we
understand how we can create our own
data types now let's go ahead and see
what are the rest of the benefits using
object oriented programming okay so
until now we understood how to assign
attributes to instances we should also
understand now how we can create some
methods and execute them on our
instances now if we will take as an
example the built-in class of string
then you know that we have some methods
that we can go ahead and execute for
each of our strings and for this example
you can see that i grab an instance of a
string that i named random str and then
i go ahead in the next line and execute
the upper method which if you remember
is responsible to grab all the letters
and turn them to uppercase now the
biggest question here is how we can go
ahead and design some methods that are
going to be allowed to execute on our
instances well the answer is inside our
class so we could go inside our class
and write some methods that will be
accessible from our instances so we
could go ahead and say def
and give our method a name now a good
candidate for a method that we'd like to
create now is actually calculate total
price because as we understand it could
have been nice if we were to have a
method that will go ahead and calculate
the result multiplying item1.price with
item1.quantity so we can get the total
price for that specific item now before
we go ahead and complete this function
then i'm going to just create one more
instance of this item by also deleting
those two lines because we understood
the example so i'm just going to change
those to item 2
like that and i'm going to use something
like
laptop and change the price to 1000 and
say that we have three of those now just
a quick side note when you will hear me
say methods then i basically mean to
functions that are inside classes
because in terms of python or in any
programming language when you have
isolated definitions with this keyword
then those are considered to be called
functions but when you go ahead and
create those functions inside classes
then those are called methods so that is
an important point that you should
understand because i'm going to call
those methods from now okay so now if i
was to continue by opening up and
closing those parentheses then you are
going to see one parameter that is
generated that python wants us to
receive intentionally now the reason
that this happens
python
passes the object itself as a first
argument when you go ahead and call
those methods now if i was to go here
and say item1 dot calculate total price
then the action that we are doing now is
calling this method but when you go
ahead and call a method from an instance
then python passes the object itself as
a first argument every time so that is
why we are not allowed to create methods
that will never receive parameters now
you will see this if i was to remove the
first parameter and say something like
pass now if i was to execute
this program now then you are going to
see type error calculate total price
takes 0 positional arguments but one was
given so in simple words what this
exception says is that python tries to
pass one argument and you are not
receiving any parameter so that is very
problematic and that is why you always
have to receive at least one parameter
when you go ahead and create your
methods now since we always receive this
parameter then it is just a common
approach to call this self it was okay
if i was to call it something like my
param or i don't know something else but
you never want to mess up with common
conventions across different python
developers so that is why just make sure
that you leave it as self every time now
if i was to go ahead and
run this program then you're gonna see
that we are not going to receive any
errors so this means that this method
has been implemented correctly now let's
see how we are going to benefit from
creating this method because it should
go ahead and create a calculation for us
using price and quantity so i will
intentionally receive here two more
parameters which we could name just x
and y for now and we could just say
return x multiplied by y and now i will
go ahead and pass in here two additional
arguments and it will be item1.price
the second one will be quantity so that
is going to work because when you call
this method in the background python
passes this as an argument and then it
passes this second argument and then
this has been passed as a third argument
so that is perfect and if i was to run
that and actually print this so excuse
me for running this
before printing it so i will
surround this
expression with this print built-in
function and i will run that and you're
gonna see 500 as expected now i could do
the exact same thing for calculating the
total price of our second item so if i
was to grab this and paste this in in
this line and actually change this to
item two and change this one to item two
and as well as this one then i will
receive
three thousand as expected and that is
how you can create a metal alright so
until that point we understood that we
can assign attributes and as well as
creating some methods that we can go
ahead and use them from our instances
directly like those two examples in that
line and as well as in that line now in
that episode we are going to solve some
more problems that we have in terms of
best practices in object-oriented
programming and things that you are
going to see in each project that is
based on oop all right so let's get
started now one of the first problems
that we have here is the fact that we
don't have a set of rules for the
attributes that you would like to pass
in in order to instantiate an instance
successfully and what that means it
means that for each item that i want to
go ahead and create i need to hard code
in the attribute name
like those in here and it could have
been nicer if we could somehow declare
in the class that in order to
instantiate an instance successfully
name price and quantity must be passed
otherwise the instance could not have
been created successfully so what that
means it means that it could have been a
great option if we could somehow execute
something in the background this second
that we instantiate an instance and
there is a way that you can reach such a
behavior and that is by creating a
special method with a very unique name
which is called double underscore init
double underscore now you might hear
this term as well as called as
constructor basically that is a method
with a unique name that you need to call
it the way it is intentionally in order
to use its special features now the way
that this is going to work is by
creating
it the following way so it will be
double underscore and as you can see i
already have auto completion for some
very special methods that are starting
and ending with double underscore now
the collection of those methods are used
to be called magic methods and we are
going to learn a lot of more magic
methods that you have in oop but the
first one that we are going to start
with will be the init double underscore
like that all right so now that we have
created this method then let's actually
see what this method does in the
background so when you go ahead and
create an instance of a class then
python executes this double underscore
init function automatically so what that
means it means that now that we have
declared our class python is going to
run through this line and then since an
instance has been created and we have
double score init method designed then
it is going to call the actions that are
inside this double underscore init
double underscore method now in order to
prove you that then i'm going to start
with a very basic print here that will
say i am created
like that now we got here one instance
and here we got another one so we should
see i am created twice and in order to
avoid confusions then i'm going to
delete those print lines from here so we
can see a cleaner picture all right so
if we were to run our program then you
can see that we have im created twice
and that is because python called this
double underscore init double underscore
method twice thanks to those two
instances that we have created all right
so now that we use the double underscore
init function in this class we should
take benefit from it and solve some more
problems in order to implement oop best
practices now if you remember in the
beginning of this tutorial i said that
one of the problems that we have till
this point is the fact that we still
hard code in the attributes in that way
by saying dot name dot price dot
quantity and that is something that we
can for sure avoid now let's see how we
can start avoiding creating those
attributes hard-coded for each of the
instances here so we can actually
benefit from the double underscore init
method that we have designed and let's
see how now we understand that for each
instance that we will create it will go
ahead and call this double underscore
init method automatically so what that
means it means that not only we can
allow ourselves to receive the sales
parameter because this is a mandatory
thing that we should do because python
in the background passes the instance
itself as a first argument we could in
addition take some more parameters and
then do something with them so as a
starter let's say that we would like to
receive one more parameter that we could
name it name and as you can see
automatically python is going to
complain how the name argument is not
filled in here so
now i could go ahead and pass in the
argument of phone for that one and for
the second one i can go ahead and pass
in the argument of laptop now once i
have created this then i can actually go
ahead and change my print line a little
bit so it will be a unique print line
where i can identify from where each
print line came from so i can go ahead
and say an instance
created
and use a column here and then refer to
the name like that and now that we have
created this then if we were to run our
program then you're gonna see unique
sentences and instances created for the
phone and as well as for the laptop all
right so now that we have done this then
there is something that is still not
quite perfect because we still pass in
the attribute of name here and here so
now pay attention how the init method
has to receive the self as a perimeter
as well and we already know the reason
for that and the fact that we have self
as a parameter here could actually allow
us to assign the attributes from the
init method so that we will not have to
go ahead and assign the attribute of
name for each of the instances we create
so what that means it means that i can
dynamically assign an attribute to an
instance from this magic method which is
called double underscore init so if i
was to say self
dot name so i'm assigning the attribute
of name to each instance that is going
to be created or created yet and i'm
making that to be equal to the name
that is passed in from here so what that
means it means that now i can allow
myself to delete
this line and then
this line so as you can see now i have a
dynamic attribute assignment thanks to
this self.name equals name that we have
wrote here and to test that the
attribute assignment worked then i can
go down here and use two more lines that
will look like the following so i will
print item
item1.name and i will also print item2
dot name and in order to avoid
confusions then i'm going to get rid of
this line so we could only see the print
lines from here and now if i was to run
that then you can see that we receive
phone and laptop so it means that we
were able to assign the attributes
dynamically and that is perfect and now
that we get the idea of that then we
should also do the same for the rest of
the attributes that we'd like to receive
so we also got the price and quantity to
take care of so i'm going to go to my
init method and i'm going to receive
again
price
and quantity and i'm going to do the
exact same thing so i'm going to assign
the attribute of price and that will be
equal to
price and the quantity will be equal to
the quantity and you can also see that
again python complains about the price
and the quantity not being passed in
here so i can say 100 and then 5
and then i can delete those
and then i can do the same here i could
pass in 1000 and then 3 and delete those
and in order to prove you that this is
going to work then i'm going to copy
myself a couple of times and change this
to quantity i mean
price
this one will be price as well
this one will be quantity and this one
as well and now if i was to run that
then you can see that the results are as
expected so that is a way that you
should work with the double underscore
init method you should always take care
of the attributes that you want to
assign to an object inside the double
underscore init method meaning inside
the constructor now a couple of side
notes that are quite important to
remember when we work with classes now
when we go ahead and use the double
score init method this doesn't mean that
we cannot differentiate between
mandatory parameters to non-mandatory
parameters so say that you currently
don't know how much you have from a
specific item then you can go ahead and
by default receive this quantity
parameter as zero because it is
realistic situation that you currently
don't know how much phones you have on
your store so you can directly go ahead
and use a default value for that for
example
zero and then this will mean that you
will not have to pass in those five and
three here and now in order to show you
the results of that if i was to run our
program then you can see that we
received zero twice for those two prints
in here so that is something that you
want to remember and one more quite
important point that i'd like to talk
about now is the fact that you can
assign attributes to specific instances
individually so say that you want to
know if the laptop has numpad or not
because some laptops are not having the
numpad on the right side of the keyboard
but this is not a realistic attribute
that you would want to assign to a phone
and that is why you can go ahead and let
me delete those print lines by the way
and that is why you can go ahead and say
something like item two dot has
numpad equals to false like that and
that is something that you want to
remember because the fact that you use
some attribute assignments in the
constructor doesn't mean that you cannot
add some more attributes that you would
like after you instantiate the instances
that you would like to alright so now
that we understood this then there is
still one small problem that is left
that we need to solve now pay attention
how the calculate total price still
receives the x and y as parameters and
the question that we ask now is
why it still receives those parameters
well we could for sure now not receive
those parameters because as we know for
each method that we design in classes
then the object itself is passed in
argument and i know that i repeated this
couple of times but this is where i fail
to understand classes so that is why it
is very important to understand this
behavior and we already know that the
object itself passed as an argument so
that's why we receive self and so this
means that now we could just return
self.price multiplied by self.quantity
and this will mean that we don't really
have to receive those parameters because
we assign those attributes
once the instances has been created so
this means that we have access to those
attributes throughout the methods that
we are going to add here in this class
in the future so in order to test that
this works then i'm going to
delete this example for now and i'm
going to say print item 1
dot
calculate total price so we will be able
to return the result here and i will do
the same for
item
two um sorry only this one now to show
some real number other than zero then i
will go ahead and pass in here
quantities so i will say one and
three for example because i don't want
to multiply a large number with a zero
and that could come from here so i will
run that and you see that we receive the
expected results so now we completely
understand the big picture how to work
with the constructors in classes and
what are the best practices that you
should go ahead and implement all right
so now that we understood this then we
might think that we have done everything
perfectly but actually i want to show
you what will happen if we were to pass
in here a string besides
an integer and run our program so if we
were to run that then you can see that
we are screwing things up here because
this function for example thinks that it
should print the string
three times because you'll see we have
1000 multiplied by three that is being
returned in here so it shows us one
thousand once
one thousand
twice and then one more time so what
that means it means that we have to
validate the data types of the values
that we are passing in so there are a
couple of ways to achieve this and one
way is by using typings in the
parameters that you're declaring inside
here so a great starter will be for
example to declare that a name must be a
string now let me first take this back
and change those to integer and then go
here and design those parameters so in
order to specify a typing then you
should go ahead and create a column sign
followed by the type of the data type
that you expect to receive here so if i
was to pass in here only the object
reference to the class of str then it
will mean that it will have to accept
strings only and i can preview that by
changing this to an integer and you're
gonna see that we have a complaint here
that says expected type str got int
instead and that is perfect so now that
we have done this then i'm going to do
the same for the price itself and price
we could actually
do the same thing with it
by passing in float now when we pass
float it is okay to also pass integers
and that is something very unique with
floats and integers together so that is
okay to use the typing of float and for
the quantity we don't need to specify a
typing because the fact that we passed a
default value of integer already marked
this parameter as to be integer always
so that is why for example if i was to
leave this as it is and change the
quantity to a string then you're gonna
see that it is going to complain because
the default value is already an integer
so it expects for an integer all right
so those things are actually great
setups to make our init function more
powerful but we might still want to
validate the received values in the
following way so say that you never want
to receive a negative number of quantity
and you never want to receive a negative
number of price so that is something
that you cannot achieve by the typings
in here but there's actually a great way
to work this around and that will be by
using assert statements now a third is a
statement keyword that is used to check
if there is a match between what is
happening to your expectations so let's
see how we can get work with assert so
i'm actually going to delete this from
here and i'm going to organize our init
method a little bit i'm going to say
here a comment and i will say assign to
self object
and i will say up top something like
run validations to the received
arguments
all right so now it is a great idea to
validate that the price and quantity are
both greater than or equal to zero
because we probably don't want to handle
with those when they are negative
numbers and we want to crash the program
so we could say assert and pay attention
that i use it as a statement not a
built-in function or something like that
and i can say here
price is
greater than or equal to
zero now once i set this then i can also
do the same for
quantity actually so let me do that
quickly
by
this way and then once we have this then
i can actually
go ahead and run our program and you
will see that i will not receive any
arrows but the second that i change this
quantity to negative 1 for example and
this one being negative 3 then i will
have some errors that will say assertion
error now you can see that the fact that
we see here assertion error
is quite a general exception that
doesn't mean anything now what is so
beautiful with assert you can add your
own exception messages right near of it
as a second argument so
let's go up top here and go back to
those two lines so the first argument
that is passed to the statement is the
statement that would like to check but
if we were to say here comma and use a
string to say
actually a formatted string and i can
say
price
and then refer to the value of it
is not greater than
0 like that
i can add an explanation mark here and i
can use the same thing
copy that with a comma and paste this in
here and change this quantity
and then refer to the value of it
and say that it is not equal to i mean
greater than or equal to zero so it
needs to be actually changed to greater
than or equal to
like that
and same goes for
here
and i have some
space here that should be deleted all
right so now if i was to execute our
program then you can see that we receive
assertion error quantity
minus one is not greater or equal than
zero so i should delete this
then here for that and now it is perfect
so now we understand that using the
assert statement could allow us to
validate the arguments that we receive
and also it allows us to catch up the
bugs as soon as possible
before going forward with the rest of
the actions that we like to take within
this program so let me actually change
those back to valid values like that
and that is perfect alright so until
this point we learned about how to work
with the constructor and we also learned
about how to assign different attributes
to instances that are going to be unique
per instance which means that you can go
ahead and create as much as instances as
you want and you have the control to
pass whatever values you'd like to for
the name price and quantity now consider
a situation that you'll want to make use
of an attribute that is going to be
global or across all the instances now a
good candidate for example of this could
be a situation that you'll want to apply
a sale on your shop so this means that
you want to go ahead and having the
control of applying some discount for
each one of the items and that is a good
candidate for creating an attribute that
is going to be shared across all the
instances now we call those kind of
attributes class attributes and the kind
of attribute that we have learned till
this point is actually called in a full
name instance attributes so about
instance attributes we know everything
and we learned how to work with it but
we did not work it with the other kind
of the attributes which we will do in
this tutorial which is called again a
class attribute so a class attribute is
an attribute that is going to be belong
to the class itself but however you can
also access this attribute from the
instance level as well let's go ahead
and see a good candidate for a class
attribute that you want to go ahead and
create it so that's gonna be going to
our class here and just in the first
line inside our class i can go ahead and
create a class attribute so let's go
ahead and create an attribute like pay
rate equals to 0.8 and the reason that
i'm doing this is because i said that
there is going to be 20 percent of
discount so i probably want to store an
attribute that will describe how much i
still need to pay
so i will say here the pay rate after
20 percent discount like that okay so
now that we have created this then let's
see what are the ways that we can access
this attribute now if i was to go down
and actually deleting one of those and
say something inside this print line
that will look like the following so i
will try to access to the reference of
the class itself so i'm not going to
create an instance like that besides i'm
just going to bring in the reference to
the class level itself and i'm going to
try to access this attribute by saying
pay underscore rate now if i was to run
that then you're going to see that as
expected we see this class attribute
because that is a way that you can
access those class attributes now this
might be confusing but i said a minute
ago that you can also access those class
attributes from the instance level well
let's see if that is true so if i was to
duplicate those lines twice by using the
shortcut of control d
then let's go ahead and change those to
item one
and this one to item two now see how i
try to access the pay rate attribute
from the instance although we don't have
such an instance attribute now if i was
to run that then you're gonna see that
we still have the access to see that
class attribute well that might be
confusing and that might be hard to
understand why that is happening well
there is actually something that we need
to understand when we work with
instances in python so when we have an
instance on our hand then at first this
instance tries to bring the attribute
from the
instance level at first stage but if it
doesn't find it there then it is going
to try to bring that attribute from the
class level so what that means it means
that item one did some thinking here and
say to itself okay so i don't have this
attribute right in here because that is
just not an attribute that assigned to
me so i'm going to try to search that
from the instance level and then i'm
going to find it and print it back so
that is exactly what is happening here
item 1 and item 2 are instances that
could not find the pay rate attribute on
the instance level so both of them went
ahead and tried to bring this attribute
from the class level and since it really
exists in the class level then we were
able to access those now to even give
you a better idea of what is going on
here then i'm going to do one more
additional thing now i will delete this
first print line and i will go ahead and
delete those attributes from here as
well now there is a built-in magic
attribute not a magic method that you
can go ahead and see all the attributes
that are belonging to that specific
object and that is achievable by using
this double underscore dict double
underscore like that so this will go
ahead and try to bring you all the
attributes that are belonging to the
object that you apply this attribute and
want to see its content so i will go
ahead and
copy this one and paste this in for the
instance level as well so this should
give me all the attributes for class
level
and the second line
should do this for the
instance level all right and if i was to
run that then let's explore the results
for a second now you can see that at the
first line we see this pay rate
attribute but in the second line we
never see it we see name price and
quantity and you can also pay attention
that this magic attribute is actually
responsible to take all the attributes
and convert this to a dictionary and
that is from where the
keyword coming from it is just a
shortened version of a dictionary so
that is a very useful magic attribute
that you can go ahead and use if you
just want to see temporarily for
debugging reasons all the attributes
that are belonging to some object all
right so now that we understood this
then let's take it to a real life
example and come up with a method that
will go ahead and apply a discount on
our items price so that will be by
creating a method that will be belong to
each of our instances and that means
that we can go ahead and come up with a
method that we could name apply discount
so let's go ahead and start working on
this so i'm going to say def apply
discount and pay attention that i'm
using a new method inside a class here
so
right inside of this then at first we
need to figure out how we are going to
override an attribute that is belonging
to an instance and we already know that
we can do that with the self keyword so
it will be self
dot price
and that will be equal to self.price
meaning the older value of this
attribute
multiplied by the pay rate now you might
expect that we could access this
directly like that but if you remember
that is actually belonging to the item
class itself now this might be confusing
because this method already inside this
class so you might think already that
you can access it directly by saying pay
rate because it is already inside the
class but that is actually not going to
work because you can either access it
from the class level or the instance
level as we understood previously so i
can go ahead and say item dot pay rate
like that and there you have a method
that can go ahead and basically override
the price attribute for one of your
items now to show you that this works
then i can only use one instance for now
and i can go ahead and call this method
by say apply discount and i can also
now try to print the attribute of price
for this item
one and we should see 80 right so if we
were to run that then we're going to see
that we are going to receive 80.0 as
expected now we should not forget the
option that you might also want to have
a different discount amount for a
specific item so say that one day you'll
have 20 items and only for the laptop
you want to have a 30 discount but it is
going to be a bad idea changing the
class attribute to 0.7 because it will
affect all the items that you have right
now on your hand so what you can do
instead is you can assign this attribute
directly to one of the instances that
you would like to have a different
discount amount for so let's go ahead
and see an example for this so i will
allow myself to bring back the item of
laptop and then what i can do to apply a
30 discount for this item is assigning
the exact same attribute to the instance
so i can go ahead and use a item tool
dot pay on the score rate
is equal to
0.7 now what will happen here is that
for item 2 it will find the attribute of
pay rate in the instance level so item 2
does not really have to go ahead to the
class level and bring back the value of
pay rate because at first look it is
going to find it in the instance level
but for item 1 it is different it is
still going to read from the item level
which is going to be 0.8
so now if we were to try to use item two
dot apply discount and as well as
printing the price now then let's see
what will happen so i will uncomment
this line to not see this print for now
and i will go ahead and execute our
program now you can see that we still
however receive 800
and what this means this means that the
discount that has been applied is still
20
and where this is coming from well this
is coming from this method here that no
matter what we try to pull the pay rate
from the class level so a best practice
here will be to change this to self and
that way if we overwrite the pay rate
for the instance level then it is going
to read from the instance level but for
item one if we try to access the pay
rate from the instance level then this
is still great because we did not assign
a specific pay rate for item one so it
is going to pull that from the class
level now if we were to try to run that
then you're gonna see now that we have
expected results and if we were to also
uncomment the first print line for the
item one and rerun our program then you
can see that for item one we had twenty
percent discount and for item two we had
thirty percent discount so when it comes
to accessing class attributes you might
want to reconsider how you want to
access them when you come up with some
methods and specifically for creating a
method like apply discount it is a great
idea to access it from the instance
level so you also allow the option of
using a pay rate that is assigned to the
instance level okay so now that we
understood completely about the
differences between a class two and
instance attribute let's jump ahead to
the next topic now you see that i have
deleted those print lines that i have
down below and i came up with five
instances that i have created here so
you might also want to create those five
instances immediately so that is why i
will recommend you to go ahead to my
repository accessing this class
attributes directory and then code
snippets and then
go ahead and copy the code from these
five underscore items.py file okay so
considering a situation that your shop
is going to be larger in the future
meaning that you are going to have more
items then the more items that you are
going to have the more filtration like
things that you want to do in the future
but what is problematic currently with
our class is the fact that we don't have
any resource where we can just access
all the items that we have in our shop
right now now it could have been nicer
if we could somehow
have a list with all the item instances
that have been created until this point
but currently there is not an approach
that will give us a list with five
elements where each element will
represent an instance of a class so in
order to come up with such a design then
here is a wonderful candidate for
creating a class attribute that we could
name all and once we do this then we're
gonna see how we are going to add our
instances to that list so i will go
ahead and start by going here and use an
old attribute so it will be
all
equals to an empty list now we need to
figure out how we are going to add our
instances for each time that we are
going to go ahead and create an instance
now if you remember the double
underscore init method is being called
immediately once the instance has been
created so it might be a wonderful idea
going down below inside this double
underscore init method and use a code
that will be responsible to append to
that list every time that we create an
instance and that will be as easy as
saying something like the following so
first you could pay attention that i
actually wrote some commands in this
double underscore init function like run
validations and assign to self object so
it might be a great idea to start with a
comment here that will say actions
to execute just to really have a great
separation between the different things
that we are doing so now inside here i
can say item
dot all and you can see that i use the
class object first and then that is a
list so i can use
dot append and then i will just append
the self object now we know that self is
actually the instance itself every time
that it is being created so once we go
ahead and launch such a command inside
the init function then for each instance
that is going to be created this whole
list is going to be filled with our
instances now to show you that i can
jump a line after we create the
instances and we can say print
item dot all and now if i was to run our
program then you are going to see that
we are going to have a list with five
instances if i was to scroll right a bit
then you can see that i have exactly
five elements and that is perfect now
that's going to be extremely useful if
you want to do something with only one
of the attributes of your instances so
say that you would like to print all the
names for all of your instances then you
can use easily a for loop to achieve
such a task so we can go ahead and say
for
instance
in
item dot all and you can say print
instance dot name and once we come up
with this then you can see that we have
all the names for all the instances that
we have created so that is going to be
useful here and there especially if you
know how to use the filter function for
example to apply some special things on
some of the instances that are matching
your criteria all right so now that we
understood this then let's also take
care of one problem that we saw
previously now if i was to use a ctrl z
a couple of times
and still use this print item.all
now you could see that the way that the
object is being represented is not too
friendly now it could have been nicer if
we could somehow change the way that the
object is being represented in this list
here now there's actually a way to
achieve this by using a magic method
inside our class now there is a magic
method that is called
double underscore repr and repr stands
for representing your objects so that is
why you can actually go ahead and use
this magic method and then you will have
the control to display your objects when
you are printing them in the console now
i actually recommend watching a video
that compares between a method that is
similar to it which is called double
underscore str and you can take a look
in the description of this entire series
to actually watch the video that i'm
talking about all right so let's go
ahead and use the repair method to
understand how this is going to work so
i'm going to say def inside our class
and i'm going to use double underscore
re pr double underscore and as expected
it will receive the self now what we can
do now is returning a string that will
be responsible to represent this object
now obviously we don't want to use
something that is not unique for each of
the instances because say that i was to
use now return item something like that
and
run our program then you can see that
i'm going to receive a list with this
string five times but it is going to be
hard to identify
which
instance represents each string here so
it could be helpful if we were to return
a string that could be unique so i'm
going to close the console here and go
ahead here and use a formatted string
and in order to make this unique it is a
best practice to represent it exactly
like we create the instance
like that so what i'm going to do here
is leaving the item and use a
brackets opener and the closure and then
i'm going to make the return string here
as much as equal as possible to the way
that we create
those instances so i will start by
typing here single quotes to escape from
the double quotes that are coming from
here and i'm going to refer to the value
of name by using self.name and then i
will leave my single quotes and i will
use a
comma like that and then i will go ahead
and refer to the value of our price i
will use one more comma and i will say
self.quantity
now if we were to execute our program
again then you can see that now we
receive a list that is way more friendly
than what we have seen previously and
you can also see that this
first element for example is quite
equivalent to this line here now you
might be curious why i worked so hard to
return the representative version of our
objects the same way that we create them
so that is just a best practice
according to python's documentations
because it will help us to create
instances immediately by only the effort
of copying and pasting this to a python
console so if you think about it right
now if you open a python console and you
import this class then it will be as
easy as grabbing this
and pasting to the python console and
then you will have an instance being
created so that is the single reason
that i have came up with this approach
and also for sure i just wanted to
return a unique string that will really
represent our instance and you can see
that it is very easy to identify the
instances of our class with this list
and with this approach all right so
until this point we understood how we
can change the way that we represent our
objects and we also understood how we
can access to all of our instances by
this class attribute that we
intentionally named all now in this part
we are going to take a look to solve one
more problem that we have in terms of
best practices when we are going to
extend this application and add more
features now you can see that until this
point we maintain our data as code in
this main.py file by only instantiating
those five items now when we will look
to extend this application and add some
more features then we might have a
harder life to add those features
because the actual data and the code are
maintained in the same location meaning
in the same main.py file now you could
have think about creating a database
that will maintain this information but
i want to keep things more simple for
the purposes of this tutorial and that
is why i'm going to use something that
is called csv that you might have heard
of
csv stands for comma separated values so
this means that you could go ahead and
use a csv file and you could store your
values as comma separated where each
line will represent a single structured
data and csv is a great option here
because it allows the data to be saved
in a table structured format all right
so let's go ahead and create a csv file
and i will actually go ahead and name
this
items.csv like that and i will go ahead
and paste in some
csv content that will be responsible at
the end of the day represent the same
data that we look to have here so you
can see that at the first line i have
name price and quantity and you can see
that those are comma separated so those
represents the columns that we are going
to have as the data that we are going to
maintain and in the second line and
further we are going to have some data
that will represent the actual data that
we look to maintain so if we were to now
split the panes then we can see that
those are quite equivalent and now we
should only look for a way to read this
csv file and actually instantiate those
objects now you can see that i have a
suggestion by pycharm to install a
plugin that will support csv files so
i'm going to just click on that and
install those plugins and you can see
that i will have a csv reader here and
we will see if we will be able to see
this data in a table which will be a lot
nicer so let's go ahead and install this
and now you can see that i have some
more options that i can actually go
ahead and use from here i know that this
is quite small but actually you have
some tabs that you can go ahead and
click on them and if i was to click on
table editor and actually
give this
file more focus then you can see that i
actually have the best way to read this
data now you can see that i have my
columns you can see that i have my rows
and that is quite nice now i can really
go ahead and visualize my data more
nicer and it is just more common way to
maintain your data okay so now that we
understood how csv files are working
let's go ahead and read our csv files
and instantiate the instances in a
generic way so it makes sense to delete
those five lines and i'm going to use
those lines
below the apply discount and use a
method that i could name instantiate
from csv
like that now you can see that this one
is also going to receive self because if
you remember i said that in each method
that we will design we need to receive
at least one parameter that will be
passed as the instance itself because
this is how python oop works now the
problem is we are not going to have any
instances on our hand to call this
method from the instance because this
method is actually designed for
instantiating the object itself so this
means that this method could not be
called from an instance so the way that
this is going to be solved is by
converting this method into a class
method now a class method is a method
that could be accessed in the following
way so i will use this line to delete
that and it could be accessed from the
class level
only so this will look like item
dot instantiate from csv and then in
here we will probably pass our csv file
so this method should take full
responsibility to instantiate those
objects for us so now that we understood
this let's go ahead and see how we can
create a class method so for sure we
need to delete the self and i know that
we have errors but we are going to solve
each one of those just in a second now
in order to convert this to a class
method we need to use a decorator that
will be responsible to convert this
method into a class method now
decorators in python is just a quick way
to change the behavior of the functions
that we will write by basically calling
them just before the line that we create
our function so we could use the add
sign and use the class method
in here and then this instant sheet from
csv method will be a class method all
right so now that we understood this
then we should also understand one more
piece of information before we go ahead
and design this method now i want to
show you what will happen if i was to
delete the entire name and try to
recreate this function here and i will
just say instantiate
from csv again now pay attention what
will happen if i was to open up and
close the parentheses now you can see
that it still receives a parameter but
this time it is named cls
now what is going on here and the thing
that is going on here is the fact that
when we call our class methods then the
class
object itself is passed as a first
argument always in the background so it
is a bit like the instance where it is
also passed as the first argument but
this time when we call a class method in
this approach then the class reference
must be passed as a first argument so
that is why you should still receive at
least one parameter but we probably
understand that we could not name this
self because that is just going to be
too much confusing okay so now let's go
ahead and write some code to read the
csv file and instantiate some objects
now i'm going to go up top first and i'm
going to import a library that is called
csv so i will go here and i will use an
import csv line because that will be the
library that will take full
responsibility to read the csv file and
then we will see how we can instantiate
some objects all right so now i can go
ahead and use a context manager to read
the items.csv file now both of those
files are located in the same location
so i can just directly say wait open
items dot csv
and the permission that i will be
passing here could be r because we only
look to read this and i will say as
f
like that now inside this open i will go
ahead and use some method to directly
read this csv which at the end of the
day will be responsible to convert this
into a python dictionary so i will say
reader is equal to csv
dot dict reader like that and i will
pass in the content of our file like
that now this method should go ahead and
read our content as a list of
dictionaries but at the end of the day
we should also go ahead and convert this
into a list so i will go ahead and
create one more variable that will be
equal to items and i will just convert
the reader into a list and that's it and
now that we have completed the actions
that we wanted to complete by reading
this csv file let's go ahead and use a
shift tab to indent out and now before
we go ahead and instantiate some objects
let's go ahead and see the results of
iterating over the items list now i will
go ahead and use for item in
items
and then i will just use print items to
show you the behavior of that and excuse
me it should be item all right so now
that we understood this then let's go
ahead and see what we have in those
lines so after our class definition we
only go ahead and call this
item.instantiate from csv method so if i
was to
run that then you can see that i receive
some dictionaries in separated lines and
that is because i iterate over a list of
dictionaries in here and that is just
perfect all right so the only thing that
we miss right now is creating instances
now besides printing those then we could
now say something like item and open up
and close parentheses
and this should be enough to instantiate
our instances now i can go ahead and
pass my arguments in here by basically
reading the keys from a dictionary so i
can say name
is equal to item dot get
and that will
receive name and now i can add a comma
and duplicate this line twice and change
those accordingly so this will be price
and this will be quantity and now i need
to replace my key names so it will be
price here and then quantity right there
and now let's go ahead and see what will
happen if i was to call this method and
as well as calling the attribute of
item.all
because this one stores all the
instances inside the list now if i was
to go ahead and run it then you can see
that i have some errors now you'll see
that the errors are related to the price
and you can see that we receive is not
greater than or equal to zero now let's
go ahead and fix this very quickly so in
the items.csv you can see that those are
actually integers that are greater than
zero so the problem is probably the fact
that those are passed as strings so we
need to go ahead and pass those as
integers so i'm going to convert those
into
int
like that and
now let's go ahead and see if we will
have any problems as i expect to have
any problem because the quantity should
complain about the same thing and you
can see that this is exactly what is
going on here so i can use the same for
quantity
like that and
work with that and you can see that now
we see our instances perfectly now i
want to show one more problem that we
could have in the future and we should
avoid now so those three lines are going
to work with this
structure of data but if i was to change
the price of our keyboard to something
like
74.90 something like that
and re-execute our
file then you can see that we will
receive some problems so we need to
convert the price not to an integer but
to a float like that and that is the
only way to get over this because we
don't want to convert the price to an
integer directly because it could be
float so now we could go ahead and
execute and you can see that now it
works perfectly although we see the
prices as 100.0
but that is something that we will look
into it in the future but for now it
works perfect and now we are ready to
jump on to our next topic okay so now
that we completely understood the class
methods let's go ahead and also
understand what static methods are now a
static method should do some work for
you that has some logical connection to
a class so for example if you want to
check if a number is an integer or a
float then this is a good candidate for
creating a static method because this
has some connection to the class that we
work with so it makes sense to check if
a price of an item has a decimal point
and by saying has a decimal point i
obviously count out those that are point
zero now to be honest static and class
methods could look very alike to you but
we will explain the main differences
very soon okay so i will use those lines
to create our first static method now
let's go ahead and use the def keyword
and we will name this method is
underscore integer because we said that
we'd like to write a static method that
will check if a received number is an
integer or not now if i was to open up
and close parentheses this would
obviously receive itself now i want you
to take a closer look what will happen
if i was to change this method into
being a static method and the approach
is going to be pretty much the same like
we have done
with the class method we will use a
decorator that is called static method
and this should be responsible to the
conversion so i will go ahead and
use this line and i will say at static
method like that now pay attention
how the received perimeter turned into
the regular orange color that we are
familiar because that is just a regular
parameter that we receive now this means
that the static methods are never
sending in the background the instance
as a first argument and that is unlike
the class methods the class methods are
sending the class reference as a first
argument and that is why we had to
receive the cls and that is why it is
intentionally colored with purple but
with static methods we never send the
object as the first argument so that is
why we should relate to the static
method like a regular function that just
receives parameters like we are familiar
with isolated functions now i will go
deeper on this just in a few minutes but
let's go ahead and finish up our static
method first so this should receive
num as one parameter because we should
receive at least something to check if
it is an integer or not all right so now
that we are inside this method
then i can go ahead and use a couple of
if statements to check if the received
argument is an integer or not now if you
remember we said that we'd like to
we will count
out the floats that are
decimal that are 0.0 okay
meaning
for example 5.0
10.0 and so on all right so now that we
understood this let's go ahead and use
an if statement here so if and we will
call the built in function that is
called is instance
and this should receive two arguments
and we can understand what this function
is going to do for us it is going to
check if the
received parameter is an instance of a
float or an integer so we will pass in
as the first argument the num and as the
second argument the flow
without calling those parentheses so
only the reference to the float keyword
so this conditional should go ahead and
check if the num is a floating number or
not
now inside this if statement i will say
return
num
dot is
integer so by saying dot is integer then
i basically say
count out the floats that are decimal
that are point zero
so this means that if i was to pass in
here a number like 10.0 then this will
return false but remember that this will
enter here because it thinks it is a
float because it is represented in that
way and so the is underscore integer
should check if the point is zero and it
should return false accordingly now i
will also use an else if statement here
to basically check if it is integer by
itself so i will say el if is
instance num
and check if it is an instance of an
integer then i will just return true and
if it is just something else then i will
just say
return false like that so now that we
have designed this method then let's
take a look how we can call it so now i
will just remove this and this i'm not
actually going to instantiate anything
i'm just going to show you how you can
access to the static method so i will
just call this item dot is integer and i
will just pass in a number that i would
like to check if it is an integer or not
now for sure we like to print this so we
will see the result now let's go ahead
and pass in seven
so you can see that we receive true now
if i was to pass in 7.5 then i would
receive false and what is happening in
the background it is the fact that it
enters here but it sees that it is not
an integer so it returns false but if i
was to change this to 7.0
then this should sorry about that this
should still return
true because what is happening it is
entering inside this conditional and
then it checks if it is an integer but
we said that this method counts out the
floats that are 0.0 so it returns true
still so that is a perfect design all
right so i have came up with a new file
which i will just explain here when to
use a class method and when to use a
static method so we can completely
understand the differences between those
because i remember myself i had a very
tough time to understand why i need this
and why i need the other one so that
will be the main question that i will be
answering in this python file so don't
feel like you have to copy and paste the
code following along what i am
explaining here by listening should be
enough all right so in this file i will
just go ahead and create this class item
that we have
right and i will use pass to not receive
errors now when we will use a static
method so we will use a static method
when we want to do something that should
not be unique per instance exactly like
we have done previously so each integer
is a method that is just going to be
responsible to check if a number is
integer or not so that is why i could
allow myself to include this under the
item just like i could use this def as
an isolated function right above the
class and that was also okay but i
prefer to not do that because although
this is a method that has nothing to do
with instance that is somehow related to
the item class so that is the reason you
want to create this as a static method
like we have designed previously and the
reason that you would like to create a
class method
is for instantiating instances from some
structured data that you own so exactly
like we have done we have created a
class method that was responsible to
read the csv file and creating some
instances so as i wrote here those are
used to manipulate different structures
of data to instantiate objects like we
have done with the csv file we could
also use a class method like install
sheet from a json file
or from a yaml file those just are
different ways to maintain data in the
best practice way and that is the code
that you look to include inside your
class methods that is why they should be
existing in any class especially if you
look to instantiate hundreds of objects
on your programs so it is a great idea
to have at least one class method like
we have done in the item class now the
only main difference between a class
method and to a static method is the
fact that static methods are not passing
the object reference as the first
argument in the background it is
noticeable from the fact that we don't
have a special highlight purple in my
case for the first parameter so if you
remember if i was to go ahead and use
here a first parameter like num then you
will see that this is the first
parameter that is colored with orange
because that is a regular parameter but
that is purple because this is a
mandatory parameter that we should
receive because what i have just
explained so those are the main
differences between a static method to a
class method now if you remember i
intentionally said that the class
methods and the static methods could
only be called from the class level but
however those also could be called from
instances so as you can see i can
actually instantiate an object and call
the is integer and as well as the
instant sheet from something you can
just pass in here a number like five and
i will not receive any errors and if i
was to run the helper then you can see
that i don't have any error now i'm
going to be honest with you i never saw
a reason to call a static method or a
class method from the instance level but
that is just an option that exists i
know that it is very very confusing but
that is something you are rarely going
to see and like i said i never saw a
great reason to call a static method or
to call a class method from an instance
so my recommendation to not confuse you
is just not going with calling those
from the instance level alright so i
minimized the code that we wrote so far
in the class item now in order to start
solving the problems that we will solve
in this episode then i'm going to create
here two instances so i will say phone
one
is equal to an item and let's give it a
name like jsc phone v10
and then just
use a random price and quantity and i
will copy and paste this and use another
variable like phone 2 and i will
increase the version by 10 and let's say
that this price for the phone 2 should
be 700 all right so now that we have
created two instances of a phone pay
attention that those two items are
phones so we could think about some
attributes that could represent phones
in real life think about an attribute
like broken phones because we could have
some phones that could have been broken
and so we cannot really mark it as a
phone that we could really sell so this
means that we could go ahead and say
phone one dot broken phones
let's say that we have unfortunately one
broken phone on our hand right now so i
will go ahead and design the same
attribute for our second phone and now
that we have came up with this realistic
attribute then the next step that we
might think about could be creating a
method that will go ahead and calculate
the phones that are actually not broken
meaning subtracting the quantity by the
broken phones amount because this is
totally making sense and then we can
understand what are the phones that we
could go actually and sell them in the
future but we have a couple of problems
creating a method that will go ahead and
calculate such a thing because we cannot
really go ahead inside our item and do
this smooth enough because we don't
really have the broken phones attribute
assigned to self and we cannot actually
go ahead and create this method inside
this item class because this method is
not going to be useful for other
hundreds of items that you will go ahead
and create this just represent a phone
kind of item so in order to solve this
problem in terms of best practices in
object oriented programming then we
could go ahead and create a separated
class that will inherit the
functionalities that the item class
brings with it and that is exactly where
we could benefit from inheritance and we
could go ahead and create a separated
class that we could name phone and then
this phone class will inherit all the
methods and all the attributes that item
class has so let's go ahead and simulate
that so i'm not going to delete the
instances yet but i'm going to go ahead
here and create a class that i will name
it phone now pay attention that i will
not use a semicolon and i will use those
brackets and i will specify what class i
would like to inherit from so i will
inherit from item and then i will just
use a pass temporarily because i would
not like to use additional functionality
right now inside this class okay so now
that we have created this class then
let's go ahead and first execute our
program where at the first stage the
instances will be item instances
and this should not have any problems
because we know that we can create those
item instances and we will not receive
any errors but if we were to change
those to
phone
like that then we should still not
receive any arrows and that's just a
basic way that you could use inheritance
in order to represent different kinds of
objects when you want to do that now
this could also be applied to other
realistic programs that you want to come
up with them by your own but in my case
it totally makes sense to create some
classes where each class will represent
a kind of an item and then i could go
ahead and inherit from the item class
in each of the child classes that i will
go ahead and create in the future i
could also use another class for a kind
of item like laptop and then i could go
ahead and use a separated functionality
for that now when we talk about classes
that we inherit from then those are
considered to be called parent classes
and when we use multiple classes that
inherits from that parent class then
those are considered to be called child
classes so those are just terms that you
want to be familiar with when we talk
about object-oriented programming and
from here we will see more advanced
things that you can go ahead and do with
your child classes all right so now
let's go ahead and understand some more
advanced things about inheritance now
throughout this series we learned that
it is not a great idea to assign
attributes manually once we create those
instances and the better way to do that
is actually going ahead and creating our
constructor and pass the value that we
like to immediately in the instance
creation exactly like here so in order
to solve this then we gonna need to
figure out how we are going to do that
because creating the constructor inside
this phone class is going to be a little
bit tricky because we don't really want
to break the logic that the development
score in it brings with the parent class
but we'd also like to pass in an
additional attribute like broken phones
that we will go ahead and deal with that
attribute and assign it to the self
object exactly like we have done in the
second part of our series so in order to
keep the logic the same for this child
class and as well as receive some more
attributes then for now i'm going to go
ahead and copy the code in our
constructor and just paste this in
right inside our phone class and that's
making sense temporarily because we
receive the exact same parameters that
we should receive when we instantiate an
instance and we also have now the
control to receive some more parameters
like we want to do with the broken
phones so let's go ahead here and say
broken
so i will just scroll here and i will
say broken phones is equal to zero let's
also receive a default value for that
and let's go ahead and type in a
validation for the broken phones so i
will allow myself to just copy that and
paste this in and we'll use a third
quantity i mean broken phones is greater
than or equal to zero and i will change
this to
broken phone
like that actually broken phones and
this should
be exactly like we have done with the
quantity and now let's go ahead to the
section of assign to self object and we
can use self.broken
phones is equal to broken phones like
that
and you can see that here we have
actions to execute now it could have
been nicer if we could also create a
class attribute for the phone class and
that will mean that we could go ahead
here and say all is equal to an empty
list
and then we could go ahead and
use a phone dot all dot append like that
and now if i was to go ahead and run
this program then you can see that i
will not receive any arrows now to check
that this works then i'm also going to
pass in here one and i'm going to do the
same here as well and i'm going to
remove those all right i'm going to
remove the hard-coded attributes and the
program still works now i'd also like to
test this by applying one of the methods
that we have wrote so far and that will
be obviously a method that i'd like to
use from the parent class because we
inherit those methods so i can go ahead
and use
phoneone dot
calculate total price and it makes sense
to print this so i will go ahead and
print that and you can see that print
phone one dot calculate total price and
now if i was to run that then you can
see that i receive a result so this
means that i don't have any errors now
i'm not sure if you paid attention to
this but if i was to scroll up a bit
then you're gonna see that the
constructor in the chat class is
complaining about something and let's
hover the mouse and see what is the
warning now you can see that it says to
us call to double underscore init of
super class is missed and what that
means it means that when we initialize
the double underscore init method inside
the child class then python expects for
some function to be called intentionally
now this function is named super and
what super allows us to do it allows us
to have full access to all the
attributes of the parent class and by
using the super function we don't really
need to hard code in the attribute
assignment like we have done with the
name price and quantity and as well as
for the other validations that we have
executed every time that we want to come
up with a child class now imagine how
hard that is going to be if for each of
the child classes that we will create in
the future we will have to go through
copying and pasting a third price and
quantity and as well as doing the
assigned to self objecting in those
three lines that is going to be a lot of
duplication of code now to save us that
time that is exactly why we need to use
the super function the super function
will allow us to have the attributes
access from the parent classes and
therefore we will be able to fully
implement the best practices in
inheritance when it comes to
object-oriented programs now again this
program works because we assign the
attributes of name price in quantity for
the self object in the child class but
if i was to remove
those
three lines and as well as those two
lines now those lines are happen to be
the lines that i have copied and pasted
and try to run this program then you can
see that we receive attribute error
phone object has no attribute price and
pay attention from what line it comes
from it comes from line 21
from the item class because it thinks
that it has the attribute of price but
we never have the price attribute in the
phone level because we just deleted the
self.price is equal to price and that's
why
now we have some problems and we are
going to replace all the lines that we
have deleted with the following thing
that i'm going to just execute now so
i'm going to go to the first line of our
constructor and i'm going to say call
to super
function
to have access
to all attributes
slash methods and then i'm going to say
super
then i'm going to open up and close
parentheses and then i'm going to use
the double underscore init method like
that now you can see that the second
that i have completed this then there
are no more warnings about the
constructor in this child class and you
can also see that this double underscore
init method expects for some special
arguments now those special arguments
obviously coming from the item class
that we inherit from so if i was to pass
in here
name
and also
price and also quantity then this should
be fine now you can also ask yourself
isn't it a duplication of code the fact
that we also copied and pasted the
parameters that we receive in the child
class and yeah that is a perfect
question that is something that could be
solved by something more advanced if you
heard about keyword arguments that is
something that we can solve it with that
way and then we will not have to
duplicate the parameters that we receive
for the constructor but that is not
something that i'm going to show for
that stage i'm going to stick with it
and i'm just going to leave it as it is
now
calling the super function and as well
as the init method right after it should
be responsible to have the same behavior
like we had previously so we should
still see 2
500 for this print line and we should
not see any errors and if i was to run
the program then you can see that we
receive the expected result so that way
we implement the best practices of
object-oriented programming for each
child class that we use a separated
constructor we also gonna need to call
the super function in order to have
fully access
for all the attributes and methods that
are coming from the class that we
inherit from all right so i minimized
the code for our classes and i also left
with one instance of phone here now i
want to show you the results of the
following things so i will say print and
i will see what is the list of all in
the item class is going to bring us back
so i'm going to say
and then i'm also going to say phone.all
if you remember we implemented this
class attributes as well here so i will
minimize the code back and then i will
run our program now you can see
something very weird in here we see item
and then we basically see the result of
the repr method that comes from the item
class now the reason that this happens
because we never implemented in our epr
method inside the phone class so that's
why we see this ungeneric result of item
now you can also pay attention that we
only create an instance of the phone
class so that's not so good that we see
item in those outputs so what we could
use instead of hard coding in the name
of the class in the repr method inside
the item class then we could access to
the name of the class generically now if
i was to replace this with some special
magic attribute that will be responsible
to give me the name of the class then
this will be perfect so i'm going to
delete that and i'm going to use curly
brackets and i'm going to say self
dot double underscore class
dot double underscore name so that is a
generic way to access to the name of the
class from the instance and by doing
this then besides receiving item hard
coded string then i should receive the
name of the class that i initialized
from the very beginning so this should
be
phone because that is the only single
instance that i have right now and you
can see that this is exactly the result
that i'm receiving back so that is
perfect now i said earlier that by using
the super function then we basically
have access to all the attributes and
the methods that are coming from the
class that we inherit from so what that
means it means that we will also have
the access to the class attribute of all
that is inside the item class and i'm
talking about
that attribute all right now to show you
that then i'm going to open back the
code from the phone class and i'm going
to remove the all attribute and i'm just
going to do that right now and i'm also
going to delete the actions to execute
where i use phone dot all dot append
because we no longer having the old
attribute in the phone class and if i
was to remove those and execute our
program now then you can see that i
still receive the same result so that is
a great idea removing the old attribute
in the child class level it is a great
idea to only use the old attribute in
the parent class because by using the
super function in the child class we
will have access to the old attribute so
this means that if one day would like to
have access to all the items instances
that have been initialized including the
child classes then accessing them from
item.all should also be enough now you
might be confused how this line is
responsible to add this instance inside
the all attribute that is happen to be a
list and that's happening because by
using the super function and as well as
the init then we basically call the init
method inside the parent class now in
the latest line inside this method we
also use item.old.append
which is also going to be accessible
from the phone class so that's why
calling the all
class attribute from the item class is a
better idea because it will give us the
complete picture okay so before diving
into the topic of that episode then
we're gonna need to do some code
organization in here because as you can
see for each of the child classes that
we will go ahead and create in the
future to extend this project then we're
going to need to do this in the main.py
file because that was the only single
file that we were working with and now
that our project grows we need to start
working with multiple files so that's
why maybe working with a file that will
represent the class of item and working
with a separate file that will represent
the phone child class will be a better
idea so we will have the main.py file
dedicated for only creating instances of
those classes so let's get started with
this so i'm going to go to the project
directory and create two python files
first one we will named item.py
the other one should be named phone.py
and i'm going to take the code from our
item class
and i'm just going to grab everything
like the following and i'm going to cut
this and then i'm going to paste this in
inside of that now pay attention that i
use the csv library so that's actually
the location that i need this library so
i'm going to
just copy the import line and that
should be good enough now i'm going to
do the same process for the
phone.py and i'm going to be copying
this into the phone.py file as well but
now this file needs to import the item
class because as you can see we got an
error here so we should say from item
import item like the following and the
errors should be gone and then in the
main.py file we can basically use this
file to only instantiate instances
meaning creating data that will
represent something to python so this
means that we can go ahead and import
the class from the item file
we can do the same
from the
phone file and then we can go ahead and
do the stuff that we used to do so we
can say item dot
install sheet from csv and to verify
that this works we can also say print
item dot all like that
and if we want to run this file now to
see that this works then we can do that
and you can see that everything works
just as expected now just a quick side
note i'm not going to rely too much on
the child class that we have created in
the latest episode to show the problems
that we're going to solve in that
episode i'm going to rely
more on the item class so that it will
be easier to follow and we will not
complex things too much now that doesn't
mean that i do not recommend using child
classes or something like that but it
will be just easier to show you the
cases that i'm going to show in the
parent class so that's why for example i
deleted temporarily the import line of
the phone class and i just came up with
a random item instance that name is my
item and the price happened to be that
number i did not specify quantity
because we have a default value and now
after this line you can see that i
override this attribute by the string of
other item now the expected result is
not going to surprise anyone because we
see at the right time when we print this
attribute but we
might want to ask ourselves is that a
behavior that we always want what if we
want to restrict our users to change the
attribute of name once the name has been
set up in the initialization meaning in
that line well that's something that we
might want to achieve for critical
attributes like the name of your
instances and in our case
the name of our item so what we could do
we could actually go ahead and create
read-only so-called attributes meaning
that we have only one opportunity to set
the name of our item and then we cannot
touch the value of that anymore so what
that means it means that we can set up
this in the initialization and we should
have errors if we try to override the
value of that now that's also known as
encapsulation when we talk about the
principles of object-oriented
programming which i will be focusing
more on the future episodes but now
let's go ahead and see how we can come
up with read-only attributes how we can
restrict our users to override the
attributes after the initialization of
our instances
okay so on the left side we have the
main.py file and on the right side we
have the item.py file which we are going
to work on and inside the class i'm
going to create our first read-only
attribute now the way that you can start
doing this is by first using a decorator
and if you remember from the previous
episodes decorators are like functions
that you can pre-execute before another
function so i could go ahead and use the
property decorator and then go ahead and
create a function and here's the exact
location that i could set up the name of
our read-only attribute so for testing
reasons let's go ahead and call this
read-only name something in that kind
all right and then i will open up and
close parentheses and this will
obviously receive self because it's
going to be belong to each of the
instances and now for testing purposes
let's only go ahead and return a random
string like
a three times all right and then now
that we have done this i can go to our
main.py file and try to access this
property now pay attention that i'm
going to call those properties and not
attributes so i'm going to go here and
i'm going to try to
print item1 dot
name and now that i have wrote name pay
attention to the differences in this
drop down for read only name we receive
a totally different icon here on the
left side which stands for a property
where in here we see the f letter which
stands for a regular field so if i was
to try to print that and run our program
then obviously we will receive the
expected result but if i was to try to
set a new value for the read-only name
say that we want to change this to
something like that then you're gonna
see that pycharm is going to complain
about this and even if we try to execute
that then we will end up with an
exception that says attribute error
can't set attribute so that is how
read-only attributes so-called are
working in python you can create those
by using a property decorator before
your functions and return whatever value
you would like to return now the biggest
challenge here is going to be converting
the name attribute that we actually have
which is happen to be exactly here into
being a read-only attribute and that is
going to be a little bit challenging but
let's go ahead and start working on that
so first things first i'm going to
delete those three lines because we are
not going to use this property anymore
and i'm going to scroll up a bit and
work underneath this constructor here so
you might think that converting the name
attribute into being read only meaning a
property is as easy as doing something
like
first using the property decorator and
then go ahead and say def name
then receive self as the parameter and
then use something like return self dot
name because we already have the self
type name assigned to the self object
but actually doing something like this
is like saying to that class hey from
now on you are going to have a name
attribute that is going to be read only
and that is straightforward the effect
of the property decorator so i'm going
to leave a comment here that is going to
look like the following but if you
remember
we try to set the self.name into a new
value inside our constructor so you can
see that this action is illegal because
we have a read only property here so
when you go ahead and create a property
with the name of basically name then you
are no more allowed to set this
value anymore you are only allowed to
have access to see this back in whatever
instance you will create so that is why
if i was to hover my mouse here then
we're gonna see an error that is saying
property name cannot be set so the
pythonic way to doing this workaround to
get over this
is using one underscore before the name
of our actual attribute name that we
assign to the self object and by doing
this we earn a couple of things that are
quite important so first let me add here
an underscore and just use something
like that and then now i need to go to
my property function meaning the
property attribute and i'm gonna need to
add here the double underscore as well
because first things first i go ahead
and set up the value for my double
underscore excuse me single underscore
name into being equal to the
value of this parameter here and then i
go ahead and use one more read only
attribute that i intentionally give the
name of name and i and then i return
self dot underscore name now i can go
back to my main.py file and see what
effects those lines are having right now
on our instances so first i can go ahead
and set a name for my item and i can
access to the name of this item
by saying something like item one dot
name so i don't really have to go ahead
and use item one dot underscore name
because that is going to be a little bit
ugly and not convenient because
accessing attributes with always an
underscore before is not nice for each
of the instances that you look to access
to their attributes doing this one time
inside the class is going to make it
okay but trying to access those
attributes outside of your class meaning
from the instances is not going to turn
it into too much pretty so that is the
best way to overcome such a thing and
now if i was to try to print that
then
excuse me let me fix that quickly by
item1 dot name
and run our program then you can see
that that is working and now let's go
ahead and also see if we can set our
name into being equal to another
thing like that
see if that works you can see that i
cannot set that attribute but however i
can still see this underscore name from
the instance level and that is maybe
something that you look to avoid it
could have been a lot nicer if we could
somehow prevent totally the access from
this underscore name in here so the way
that this is achievable is by adding one
more underscore to the attribute name
now this might remind you something that
is called private attribute if you are
familiar with programming languages like
java or c-sharp that is pretty much the
same behavior of using the private
keyword before your attributes in those
kind of programming languages where it
has different principles when it comes
to object-oriented programming so to sum
up if you add one more underscore to
your attribute names meaning you use
double underscore then you basically
prevent the access to those attributes
totally outside of the class so let's
see a simulation of that so i'm going to
minimize the terminal and i'm going to
go to my item.py file and besides using
here single underscore i'm going to add
one more and then i'm going to change
this to double underscore as well and
now if we were to go to our main.py file
and
let's use here item one
dot and try to basically use
double underscore and try to access to
name now you can see that i don't even
have an auto completion from my drop
down because i don't have access to see
this attribute from the instance level
and that is something that you look to
achieve when you want to have a clean
read-only attribute and that is the way
that you can do that so if i was to try
to print this then that's just going to
complain about how it does not have the
attribute of double underscore name
in this instance
and again if i was to remove those
double underscores then i will just
access it as a property meaning as a
read-only attribute and that is exactly
what i look to have here all right so
now that we got the idea of that then we
still might be curious about how to
set a new value for the name attribute
now obviously using the property
decorator is going to turn this into
being a read-only attribute but there
are still some decorators that will
allow you to however set a new value for
this
property of name so let's see how that
is achievable so obviously that is not
going to work because it says
can't set attribute so what we can do is
we can use a new method where we can
declare that we'd like to also set a new
value for this attribute that we named
name
so the way that that's going to work is
by going to our class here and using
here one more method with a special
decorator now this decorator is going to
look like the following so i'm going to
refer to the
name because that's the property name
and then i'm going to use the dot setter
so by doing this then i basically say
hey so i still want to set a new value
for that name although
that is a property meaning a read-only
attribute so now if i was to
go down and say something like def name
and this would receive self and as well
as one additional parameter because the
additional parameter should refer to the
new value that i want to set to that
name so i will receive a parameter that
i could name something like value and
then inside here i'm only going to set
the new value for our double underscore
name because if you remember
when an instance tries to see the value
of name then we basically return
self.double underscore name so when a
user will try to set the name again to a
new value then it should execute self
dot
name equals to value and by doing this i
basically allow our users to yet set a
new value for
name
so now let's show what effect those
three lines are going to have in our
main dot py you can see that now the
error is gone i can now go down here and
use print item one dot name
and that's going to work you can see
that i have other item so this means not
only i can set a new value for my
underscore name so-called
in the initialization i can also do that
later on if i only use this convention
in here now those getters and said this
thing are always confusing in no matter
programming language you work so i will
do a final summary of all what we have
learned until this point all right so
using add property
will basically give you a control of
what you'd like to do when you get an
attribute and also by using this then
you basically convert this attribute
into being read only if i was not
implemented
these setters in
here so you can see that now when i
commented those out then this line is
going to have some problems because by
not doing this then i basically say that
hey name is read only you cannot set
that if i want to again uncomment those
back then i will have the control to set
this attribute to whatever attribute i'd
like to now by using
this statement here basically getting
the attribute then i basically call the
bunch of codes that are being executed
in here so whenever i use item1.name
then python says to itself okay you try
to get that attribute so i will go ahead
and try to execute all the lines of
codes are
that are here so that is what exactly
happening here and to show you that then
i can just use a random print function
here that will say
you are trying to
get name like that then you should see
this line being printed right before
what the actual value is because at
first
we print you are trying to print the
name and then we return the self dot
underscore name so it prints that over
here so that is what happening when you
try to
get an attribute but when you try to set
an attribute then python says to itself
okay so here you try to set an attribute
so because you set an attribute then i
should go ahead and
execute the code that is inside here
because that is the setter of that
attribute so that is why when you go
ahead and
use this decorator then you should
always receive a parameter because the
other item is going to be passed as an
argument to that parameter it is very
important to understand that and that is
why i can only allow myself to use one
line of code that will say self dot
double underscore name
is equal to the new value that you try
to
set and to show you that again i can go
here and say print
you are trying
to set and this line should appear just
before this print line because
at first i try to set
a different value for name and then i
just print it back like that okay so if
i was to run that then you can see that
at first we see the line of you are
trying to set then right after it we
actually see whatever item one dot name
is equal to now the reason that the
value is set it is because we set it
over here and then the next time i try
to get the value then those lines are
getting executed so that is the life
cycle of getters and setters and that is
the way that it works by having the
control of whatever you'd like to do
when you set a new value you can also
restrict it you can go ahead and do some
conditioning or you can go ahead and
raise some exceptions if you don't like
the value that you receive let's say
that you want to restrict the length of
the characters for the name of that
attribute all right so that is something
that you can do you can actually go here
and say if
len
of the value
is um greater than 10
then you would like to raise exception
that will say
something like
your
the name is too long something like that
and then you can say
else and then you can execute the line
that will be responsible to set that
value so intentionally i'm going to
leave it as it is because the length of
that is
nine characters so we should not have
any arrows but if i was to add here
two more characters like that and
execute it then you can see that we are
going to receive an exception that will
say the name is too long so that's how
ghettos and setters are working in
python you now have all the knowledge
that you need to play around with
different attributes and manage them the
way that you like to so i believe that
after the information that you received
in that episode you have everything that
you need to manage your attitude
successfully and play around with it and
as well as coming up with rich classes
that will have multiple attributes and
then you can set up special behaviors to
those attributes and also you can decide
that you'll not like to force to receive
those attributes in the constructor you
can decide that you can delete some
parameters in your constructor and you
can say that you will not like to assign
those to the self object immediately
when you create an instance so whatever
you would like to you have all the tools
to play around with how to manage your
attributes object-oriented programming
comes with four key principles that you
should be aware of so you will
understand how you should design your
large programs so it will be easier to
keep developing it and i'm going to talk
about those principles which are
encapsulation abstraction inheritance
and polymorphism so the first principle
will be encapsulation and we will talk
about this a little bit so encapsulation
refers to a mechanism of restricting the
direct access to some of our attributes
in a program now notice how we did a
great job in the last part where we
implemented the encapsulation principle
on our project so pay attention to how
the name attribute could not be set to a
new value before it goes through some
conditions that we set here like the
length of the character being less than
10 characters so restricting the ability
to override the values for your objects
within your setters is exactly what the
encapsulation principle is about now to
even give you a better example of
encapsulation principle then we are
going to apply similar things to an
additional attribute which is going to
be the price attribute now if we take a
quick look in that program that i have
just executed
then you can already see that i have the
ability to directly set this object into
whatever number that i like to also
negative 900 will work here so that's
probably something that we look to
change and the way that we can change
that is by implementing some methods
that will restrict the access to this
price attribute so it could have been
nice if we could have two methods that
will be responsible to increment this
price by some percentage amount and the
same goes for the discount now if you
remember we already came up with a
similar method that looks like apply
discount when we talked about class
attributes because self.pay rate
multiplied by the actual price
is actually going to change this
attribute being decreased by 20 because
pay rate is set to 0.8 if you remember
from the previous episodes so let's go
ahead and continue designing this price
attribute to totally support the
encapsulation principle so first things
first i'm going to convert this price
into being a private attribute so it
will be a great start avoiding to set
this price directly like we have seen
previously now i'm not going to just add
here double underscore besides i'm going
to grab this whole thing
i'm going to
right click and then i'm going to say
refactor rename and then i'm just going
to rename this price by setting it like
that double underscore before that now
doing this is actually going to refactor
this change on the entire class where we
try to access the price attribute so
that is a great thing so we don't really
have to change everywhere so once i have
done that then if we would also take a
look in the apply discount then you can
see that we have this being set to a new
variable name that we came up with so
now that we have done this then let's go
ahead and create a property so we will
have the ability to access the price
attribute
temporarily being only read only so i'm
going to say add property and then i'm
going to say def
price
then i'm just going to return
self.
price so that's a great starter to
restrict the access to the price
attribute because now we still have
access to the price attribute
and then we cannot set that so you can
see that if we were to try to access
item1.price
we will have some errors but we can just
access the
actual value of that where it comes from
the initialization so that's a
oh actually i see that we hit an error
that says recursion error and that's
probably because i did not add the
double underscore in here by mistake so
that's actually a great exception that
we came across right now you can see
that we are going to hit recursion error
maximum recursion depth exceeded and
that happened because i tried to return
the price without the double underscore
so
if we try to call the self.price then it
is going to try to call this function
and if we try to return that then it's
just going to loop over it again and in
some time it's going to fail with the
recursion error as you see so that's
actually a great exception that
we see now and if you see this exception
in your object-oriented programs now you
know how to handle it and if i was to
come back now to main and execute that
then you can see that the expected
result is here all right so now that we
have done this then let's go back to our
class and try to work on our methods
that will modify the attribute of double
underscore price so i will actually cut
this method from here and i will just
put that
right under the property price that we
came up with so we will have a cleaner
look now first things first you can see
that we have the apply discount and we
will also like to come up with apply
um increments
like the following and we would like to
say here
self dot
double underscore price is equal to self
dot double underscore price
plus
self dot double underscore price
multiplied by some value that we can
receive as a perimeter so we could
actually receive a parameter
that we could name increment
value
and then we could just multiply it by
that number so now that we came up with
this then let's test this up okay i'm
going to go back to my main.py and then
i'm going to call item1 dot apply
increment and then i'm just going to
pass in 0.2 so we will increment the
value of 750
by 20
now the next time that i access the item
one dot price
we should be able to see the actual
value of price which should be 900 and
if i was to run that then you can see
that the price has been incremented to
900 as expected so that is exactly
encapsulation in action because you go
ahead and you don't allow the access
directly to the price attribute besides
you modify this attribute by using
methods like apply increment or apply
discount now the same will happen if i
was to now go ahead and use item1 dot
apply
discount and you can actually modify
this method in the way that you like to
but this currently refers to a class
attribute that we use
here so this should also again apply a
discount of 20 to the 900 price we
should be able to see 720
and that's exactly what is happening
here all right so the next principle
that i'm going to talk about is called
abstraction now abstraction is the
concept of object-oriented programming
that only shows the necessary attributes
and hides the unnecessary information
now the main purpose of abstraction is
basically hiding unnecessary details
from the users now by seeing users i
basically mean people like me or you
that are going to use the item class to
create some item objects now you can see
that now we have a new program here that
has one item object that its name is my
item price being that number and we have
six from this item now you can also see
that i came up with a method that
doesn't really exist which is called
send email so that method at the end of
the day should send an email to someone
that would like to decide about this
item and it will send info about how
much money we can earn by selling all
the items and maybe about some more info
that is related to this item now
sending an email is not as easy action
just by calling it with that way
because in the background email sending
has to go a lot of processes like
connecting to an smtp server and as well
as preparing the body of the email with
an auto message that will display some
info about this item so as we can
understand we have to go through a lot
of new methods before we go ahead and
just call a send email method so to
simulate that then i can actually go
ahead and say send email so i will just
create the method that is necessary
temporarily i will use pass now as i
said we also have to go through a lot of
other processes so it is a great idea to
create methods for each of those
processes like connecting to an smtp
server
smtp server like that and i will just
say pass because we only try to simulate
the idea of abstraction here i'm not
really going to send an actual email to
someone i'm just simulating an idea of
sending an email and we will also have
to go through preparing a body for an
automatic mail prepare
body right and then i can just return a
formatted string that will say
something like hello
um
someone
we could receive this as a parameter as
well and then we can say
we have
self.name
six times right so it should be six
self dot quantity times like that
then i can say regards
to shape code so that is just a very
simple email that we can send to someone
now you can understand that we have to
call those methods inside the send email
so simulating that will be self dot
connect
and then self dot
and
prepare body
and probably we also need to go through
sending it right so we can just
say something like send here
then use pass again now you can see that
those methods
at the end of the day are only going to
be called from the send email because
those are just parts of the email
sending process that is a bigger process
that we divided into multiple steps in
this class now the biggest problem is we
will have access
calling those methods
from the instance and that is exactly
what abstraction is about abstraction
principle says to you that you should
hide unnecessary information from the
instances so that is why by converting
those methods into being private methods
then we actually apply abstraction
principles and that is achievable in
python in a way which i'm going to be
honest is not too much convenient but it
is achievable by adding double
underscore now again in other
programming languages this is achievable
by having access modifiers for your
methods like private or public and i'm
talking about
programming languages like java c-sharp
etc so if we were to convert those
methods to private methods by only
adding double underscore then those only
could be called
from the class level meaning inside the
class so if we were to try to access it
then you can see that i'm going to have
auto completion meaning i will have the
ability to access those methods
and then i will just do the same for
the other methods now this error comes
from here because we did not really
specify some argument i'm just going to
add an empty string now if i was to go
back to our main.py file then you're
gonna see that we are going to have some
troubles even if i'm going to try to
access it with a double underscore i'm
not even going to have an autocompletion
and the reason for that it is because
that is a private method so you really
have to think about your methods if you
want to make them accessible outside of
your class meaning from the instances
and that is exactly what abstraction is
about you want to abstract the
information that is unnecessary to call
it or to access it from your instances
okay so inheritance is the third
principle of object-oriented programming
inheritance is a mechanism that allows
us to reuse code across our classes now
that's something that we have totally
designed well throughout this course
because we came up with more classes
that are child classes of the item class
where each child class represents a kind
of an item
now pay attention how i changed the
import line from
phone import phone and i use the child
class of item which we came up with
which is called phone you can see that
i'm passing similar arguments and i can
still use a code that is implemented in
the parent class if we were to execute
this program then we are not going to
receive any problems because
phone
uses all the methods and attributes that
it inherits from the item class which is
exactly here and if we remember we
designed the send email method in the
parent class and we can use it from the
instance of a phone and we can also do
that for the rest of the methods that we
came up with that really affects some of
the attributes like in the
encapsulation part where we applied
the apply increment method that receives
an increment value and if we were to
test this
incrementing the price by 0.2 and then
printing item one dot price then we
should see 1200 so if we were to print
that then you can see that that is
exactly the result so that is mainly
what inheritance is about it is about
reusing the code across all the classes
and that's exactly the scenario here and
the beauty behind that is that you can
come up with more tried classes that
will represent kinds of items like
laptop keyboard camera everything that
you think about and then you can just
modify specific methods that you'd like
to according to the kind of item that
you have so that's perfectly describing
what inheritance is about all right so
the last principle that we have now is
polymorphism now polymorphism is a very
important concept in programming it
refers to use of a single type entity to
represent different types in different
scenarios now a perfect example for this
definition will be some of the functions
that we already know that exist in
python now just a quick side note
polymorphism refers to many forms poly
being many and morphism being forms so
again the idea of applying polymorphism
on our programs is the ability to have
different scenarios when we call the
exact same entity and an entity could be
a function that we just call now as you
can understand polymorphism isn't
something that is specifically applied
to how you create your classes that is
actually something that refers globally
to your entire project and in the next
few minutes we are going to see some bad
practices where polymorphism is not
applied and we are also going to see
where in python polymorphism is
perfectly applied so a great example of
where polymorphism is applied is in the
lan built-in function because the lan
built-in function in python knows how to
handle different kinds of objects that
it receives as an argument and it
returns you a result accordingly so as
you can see in here if we were to use
the land built-in function in a string
then we will receive the total amount of
characters but if we will do this in a
list then we will not receive the length
of characters of this entire expression
in here besides we will receive back the
amount of elements that are inside this
list and to show you how this is going
to work then i'm just going to run this
program and for sure the results are
just as expected so as the definition of
polymorphism says it is just a single
entity that does know how to handle
different kinds of objects as expected
all right so now that we understood that
the polymorphism is applied everywhere
in python especially in the land
building function let's also understand
where it is implemented on our project
here now you can see that i try to call
the apply discount method that is never
implemented inside the phone class and
the fact that i can use it from the item
class it is because we inherit from this
class and that is the basically reason
now if i was to go back to that main dot
py file and run this then you can see
that that is going to work because the
applied discount is a method that i can
use from the inherited item class now
that's exactly where polymorphism is
also in action because polymorphism
again refers to one single entity that
you can use from multiple objects now if
i was one day to go ahead and create
more kinds of items meaning more classes
that will represent different kinds of
items and from them to call the applied
discount method that's also going to
work because the applied discount is a
method that is going to be accessible
from all the kinds of objects so that's
exactly why you might have heard about
the terms of inheritance and
polymorphism together combined now to
show you that then let's try to create
one more class that is going to be
identical to the phone class right i'm
going to create a keyboard file and then
i'm just going to say here
class
you know what before that let's go to
phone
and
copy everything from here and paste this
in like that i'm going to get rid from
those lines
and i'm just going to leave the init as
it is i'm going to change the class name
from
phone to keyboard and i'm also going to
delete that attribute that we don't need
broken phones all right so now that we
have this then i can actually go ahead
to my main.py file and use one more
import line that will say from
keyboard import keyboard and then i'm
going to change this to keyboard
will replace this name just to make it
more realistic then i'm going to run the
same program
you can see that this works so that's
again exactly where polymorphism is in
action because we can use this single
entity from different kinds of objects
and it will know how to handle it
properly now by saying handle it
properly then i basically mean you can
have the control of how many amount of
discount you want to apply inside your
classes now because if we were to go to
keyboard and use a class
attribute exactly like we used in the
item class which was
pay rate then we're going to have full
control for all the discounts that are
going to apply to the keyboard and to
show you that i'm going to attempt
typing in pay rate and you can see that
i even have auto completion because
overriding in the child class that is
legal all right so i can just say pay
rate is equal to 0.7 and that will be it
now i have the same discount amount for
all my keyboards if i was again to run
the main.py file then you can see that
the results are just as expected we see
700 so that is the beauty behind
inheritance and polymorphism together
and the same will go for sure if we were
to decide that we'd like to have 50
discount so it will only take from me to
go ahead and say pay rate is equal to
0.5 and that's it so i hope that you
understand about polymorphism a bit
better now now just a quick side note
polymorphism is perfectly could be
implemented by using abstract classes
and that is just the identical way of
using interfaces in other programming
languages like java interface is a way
that you can implement how a class
should be
designed right so it is like a template
for a class and that is achievable by
using abstract classes which i'm not
going to cover in that part but again
polymorphism like i said is a term that
is implemented in different areas in the
whole python programming language so i
hope you had a great time learning the
object-oriented programming course now
you have a lot of tools that you can go
ahead and try to implement by yourself
on your projects which will really help
you to take you to the next step as a
developer see you next time
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.