Python Lab 7 : Object Oriented Programming in Python
Object oriented Approach not only allows developers to reuse but with the help of polymorphism , inheritance and encapsulation it allows developers to easily read,manage,update, delete and fix bugs in the code.
Class in python
A class is a code ‘template’/’blueprint’ for creating objects on which functions are performed.It’s important to note that a class just provides structure—it’s a blueprint for how something should be defined, but it doesn’t actually provide any real content itself.
class employee:
pass
Object in Python
While the class is the blueprint, an instance is a copy of the class with actual values, literally an object belonging to a specific class.This example shows that two objects for class employee have been created which are unique and have unique locations in the memory, same is also verified emp1==emp2
class employee:
pass
emp1 = employee()
emp2 = employee()
print(emp1)
print(emp2)
print(emp1==emp2)
Show Output
<__main__.employee object at 0x00000278EB851160>
<__main__.employee object at 0x00000278EB8510F0>
False
Methods in Python
Methods are nothing but functions with classes. The only difference is methods automatically pass instance as its 1st argument which is called as self.
Initialization method or __init__() method in python
__init__ is a special method in Python classes, it is the constructor method for a class. In the following example you can see how to use it. __init__ is called when ever an object of the class is constructed.Basically __init__() is the first method which you will define after creating a class.All Instance variables or object variables are mentioned inside the __init__() method.
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
emp1 = employee('sameer','joshi',50000)
emp2 = employee('test','user',70000)
print(emp1.first)
print(emp2.first)
Show Output
sameer
test
User defined methods in Python
In the beow example we have created a method named fullname() this is called as user defined method.Note , self specifies that instance/object will be passed as first argument
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
def fullname(self):
return '{} {}'.format(self.first,self.last)
emp1 = employee('sameer','joshi',50000)
emp2 = employee('ram','yadav',70000)
print(emp2.fullname())
print(employee.fullname(emp1))
Show Output
ram yadav
sameer joshi
Class Variables in python
Instance variable has to be unique for each instance/object but class variable have to be the same.Let us explain this with an example which will be common to all the employees that is raise or salary hike.
class employee:
raise\_amount=2
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
def fullname(self):
return '{} {}'.format(self.first,self.last)
def apply\_raise(self):
self.pay = int(self.pay\*employee.raise\_amount)
return self.pay
emp1 = employee('sameer','joshi',50000)
emp2 = employee('ram','yadav',70000)
print(emp1.pay)
print(emp1.apply\_raise())
Show Output
50000
100000
Example to find out total number of employees
class employee:
num\_of\_emp=0
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
employee.num\_of\_emp+=1
emp1 = employee('sameer','joshi',50000)
emp2 = employee('ram','yadav',70000)
emp3=employee('test','user',12345)
print(employee.num\_of\_emp)
Show Output
3
Class Methods and Static Methods
Unlike other methods class method and static method are not bound to any object. So you don’t need any object or instance to call these methods.
Class Method
Uptil now we have seen that the regular methods automatically takes instances as 1st arguments which is called self. Similarly class methods take class as 1st argument which by convention is called cls.To create a class method you first have to declare that you are using the below method as class method and same is done by using a decorator called @classmethod.Classmethods can also be called by objects. It is not necessary to call class variable using class name only
class employee:
raise\_amount=2
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
@classmethod
def set\_raise\_amount(cls,amount):
cls.raise\_amount = amount
emp1 = employee('sameer','joshi',50000)
emp2 = employee('ram','yadav',70000)
employee.set\_raise\_amount(4)
print(employee.raise\_amount)
print(emp1.raise\_amount)
print(emp2.raise\_amount)
Show Output
4
4
4
Static method
We saw that regular methods pass instance automatically as first argument which is called self, class methods pass class automatically as first argument which is called cls but static methods don’t pass anything automatically. So static methods are similar to our functions but they are included within class and have some logical connection with the class. In order to tell python that given method is static method we need to declare it by using decorator @staticmethod. Let see one example
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
@staticmethod
def is\_workday(date):
if date.weekday() == 5 or date.weekday() == 6:
return False
else:
return True
import datetime
date = datetime.date(2020,7,21)
print('Is it a working day:',employee.is\_workday(date))
Show Output
True
Inheritance
This allows us to inherit attributes and methods from parent class.This is useful as we can use the functionality of parent class in a subclass and then overwrite or add another functionality to it without affecting the parent class in any way.
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
class developer(employee):
pass
dev1 = developer('Divya','Shah',30000)
dev2 = developer('Nakul','Yadav',20000)
print(dev1.pay)
print(dev1.email)
Show Output
30000
Divya.Shah@abc.com
In above example we have used all the attributes from parent class.Now lets us try to create some new attributes in child class.In below example e have created a new instance variable called prog_lang for developer class
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
class developer(employee):
def \_\_init\_\_(self,first,last,pay,prog\_lang):
self.prog\_lang = prog\_lang
dev1 = developer('Divya','Shah',30000,'Python')
dev2 = developer('Nakul','Yadav',20000,'Ansible')
print(dev1.prog\_lang)
print(dev1.email)
Show Output
```
Python
Traceback (most recent call last):
File "C:/Users/Pallavi/AppData/Local/Programs/Python/Python36/my programs/oop.py", line 17, in <module>
print(dev1.email)
AttributeError: 'developer' object has no attribute 'email'
```
you can see that we got correct output when tried to print(dev1.prog_lang) but when we tried to print(dev1.email) we got an error.This is because now developer class has its own __init__() method so it will not go to the parent class for instance variable.This can be avoided by telling child class that it has to refer the parent class for instance variable like firt,last and email
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
class developer(employee):
def \_\_init\_\_(self,first,last,pay,prog\_lang):
self.prog\_lang = prog\_lang
super().\_\_init\_\_(first,last,pay)
dev1 = developer('Divya','Shah',30000,'Python')
dev2 = developer('Nakul','Yadav',20000,'Ansible')
print(dev1.prog\_lang)
print(dev1.email)
Show Output
Python
Divya.Shah@abc.com
Polymorphism
Polymorphism and Method Overriding. In literal sense, Polymorphism means the ability to take various forms. In Python, Polymorphism allows us to define methods in the child class with the same name as defined in their parent class.
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + '.'+last+'@abc.com'
def fullname(self):
return '{} {}'.format(self.first,self.last)
class developer(employee):
def \_\_init\_\_(self,first,last,pay,prog\_lang):
self.prog\_lang = prog\_lang
super().\_\_init\_\_(first,last,pay)
def fullname(self):
return 'my fullname is {} {} '.format(self.first,self.last)
emp1 = employee('Divya','Shah',30000)
dev1 = developer('Nakul','Yadav',20000,'Ansible')
print(emp1.fullname())
print(dev1.fullname())
Show Output
Divya Shah
my fullname is Nakul Yadav
@property decorator in python OOP
Property decorators allows us to access methods as attributes.Means when object emp1 will access the method fullname he will not have to use parentheses. He can access it as attribute.
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
@property
def fullname(self):
return '{} {}'.format(self.first,self.last)
emp1 = employee('sam','roberts',50000)
print(emp1.fullname)
Show Output
sam roberts
@setter in python oop
Now if we can access a method as an attribute then we should be able to provide a value to it as we do for any instance variable.This can be achieved using @setter.Same is shown in below code
class employee:
def \_\_init\_\_(self,first,last,pay):
self.first = first
self.last = last
self.pay = pay
@property
def fullname(self):
return '{} {}'.format(self.first,self.last)
@fullname.setter
def fullname(self,name):
first,last=name.split(' ')
self.first=first
self.last=last
emp1 = employee('sam','roberts',50000)
print(emp1.fullname)
emp1.fullname='Harry Potter'
print(emp1.fullname)
Show Output
sam roberts
Harry Potter
Example : Replicate bank account to print the current balance as well as the amount deposited or withdrawn
class BankAccount:
def \_\_init\_\_(self,name):
self.name=name
self.balance=0
def withdraw(self, amount):
print(self.name,'withdrawed:',amount)
self.balance -= amount
print(self.name,'account balance is:',self.balance)
def deposit(self, amount):
print(self.name,'Deposited:',amount)
self.balance += amount
print(self.name,'account balance is:',self.balance)
accountholder1=BankAccount('John')
accountholder2=BankAccount('Peter')
accountholder1.deposit(100)
accountholder2.deposit(200)
accountholder1.withdraw(50)
accountholder2.withdraw(100)
Show Output
John Deposited: 100
John account balance is: 100
Peter Deposited: 200
Peter account balance is: 200
John withdrawed: 50
John account balance is: 50
Peter withdrawed: 100
Peter account balance is: 100