All language subtitles for Object Oriented Programming with Python - Full Course for Beginners

af Afrikaans
ak Akan
sq Albanian
am Amharic
hy Armenian
az Azerbaijani
eu Basque
be Belarusian
bem Bemba
bn Bengali
bh Bihari
bs Bosnian
br Breton
bg Bulgarian
km Cambodian
ca Catalan
ceb Cebuano
chr Cherokee
ny Chichewa
zh-CN Chinese (Simplified)
zh-TW Chinese (Traditional)
co Corsican
hr Croatian
cs Czech
da Danish
nl Dutch
eo Esperanto
et Estonian
ee Ewe
fo Faroese
tl Filipino
fi Finnish
fr French
fy Frisian
gaa Ga
gl Galician
ka Georgian
de German
el Greek
gn Guarani
gu Gujarati
ht Haitian Creole
ha Hausa
haw Hawaiian
iw Hebrew
hi Hindi
hmn Hmong
hu Hungarian
is Icelandic
ig Igbo
ia Interlingua
ga Irish
it Italian
ja Japanese
jw Javanese
kn Kannada
kk Kazakh
rw Kinyarwanda
rn Kirundi
kg Kongo
ko Korean
kri Krio (Sierra Leone)
ku Kurdish
ckb Kurdish (Soranรฎ)
ky Kyrgyz
lo Laothian
la Latin
lv Latvian
ln Lingala
lt Lithuanian
loz Lozi
lg Luganda
ach Luo
lb Luxembourgish
mk Macedonian
mg Malagasy
ms Malay
ml Malayalam
mt Maltese
mi Maori
mr Marathi
mfe Mauritian Creole
mo Moldavian
mn Mongolian
my Myanmar (Burmese)
sr-ME Montenegrin
ne Nepali
pcm Nigerian Pidgin
nso Northern Sotho
no Norwegian
nn Norwegian (Nynorsk)
oc Occitan
or Oriya
om Oromo
ps Pashto
fa Persian
pl Polish
pt-BR Portuguese (Brazil)
pt Portuguese (Portugal)
pa Punjabi
qu Quechua
ro Romanian
rm Romansh
nyn Runyakitara
ru Russian
sm Samoan
gd Scots Gaelic
sr Serbian
sh Serbo-Croatian
st Sesotho
tn Setswana
crs Seychellois Creole
sn Shona
sd Sindhi
si Sinhalese
sk Slovak
sl Slovenian
so Somali
es Spanish
es-419 Spanish (Latin American)
su Sundanese
sw Swahili
sv Swedish
tg Tajik
ta Tamil
tt Tatar
te Telugu
th Thai
ti Tigrinya
to Tonga
lua Tshiluba
tum Tumbuka
tr Turkish
tk Turkmen
tw Twi
ug Uighur
uk Ukrainian
ur Urdu
uz Uzbek
vi Vietnamese
cy Welsh
wo Wolof
xh Xhosa
yi Yiddish
yo Yoruba
zu Zulu

Original subtitles

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.