Unit 3
Unit 3
1
Object Oriented Features
2
Classes and Objects
class Classname(object): # or class Classname:
""" docstring describing the Class """
attributes
def __init__(self):
def method1():
def method2():
instancename = Classname()
3
_init_()
• The __init__() function is a special method to initialize the variables
• The __init__() function is called automatically every time the class is being
used to create a new object.
• The self parameter is a reference to the class instance itself, and is used to
access variables that belongs to the class.
• ‘self’ is a variable that contains the memory address of the instance of the
current class.
• It does not have to be named self , you can call it whatever you like, but it
has to be the first parameter of any function in the class
4
Example
class Employee:
def __init__(self, name, age): # Constructor
self.name = name
self.age = age
def empdetails(self):
print("Employee name is " + self.name)
print("Employee age is " , self.age)
e1 = Employee("John",40)
e1. empdetails()
5
Example
class Employee:
def __init__(self, name= "xyz", age=30):
self.name = name
self.age = age
def myfunc(self):
print("Employee name is "+ self.name)
print("Employee age is " , self.age)
7
Example: Instance Variable
class Sample:
def __init__(self): Output
self.x=10 x in S1= 10
def modify(self): x in S2= 10
x in S1= 11
self.x+=1
x in S2= 10
s1 = Sample()
s2 = Sample()
print('x in S1= ',s1.x)
print('x in S2= ',s2.x)
s1.modify()
print('x in S1= ',s1.x)
print('x in S2= ',s2.x) 8
Example: Class / Static Variable
class Sample:
x = 10 Output
x in S1= 10
@classmethod # built-in decorator statement x in S2= 10
def modify(cls): x in S1= 11
cls.x+=1 x in S2= 11
x Value= 11
s1 = Sample()
s2 = Sample()
print('x in S1= ',s1.x)
print('x in S2= ',s2.x)
s1.modify()
print('x in S1= ',s1.x)
print('x in S2= ',s2.x)
print('x Value= ',Sample.x)
9
Example : Class Variables
class Employee: print("Number of employees before creating
totemps = 0 Instances:", Employee.totemps)
payhike= 1.04 emp_1 = Employee('Rishi',70000)
def __init__(self,name,pay): emp_2 = Employee('Shwetha',80000)
self.name= name print("Number of employees after creating
self.pay = pay Instances:",Employee.totemps)
Employee. totemps +=1 print ("Pay of Employee 1:",emp_1.pay)
def apply_hike(self): print ("Pay of Employee 2:",emp_2.pay)
self.pay = int(self.pay * self.payhike) emp_1.apply_hike ()
emp_2.apply_hike()
print ("Pay of Employee 1 after hike:",emp_1.pay)
print ("Pay of Employee 1 after hike:",emp_2.pay)
Output
Number of employees before creating Instances: 0
Number of employees after creating Instances: 2
Pay of Employee 1: 70000
Pay of Employee 2: 80000
Pay of Employee 1 after hike: 72800
Pay of Employee 1 after hike: 83200 10
Example : Class Variables
class Employee: print("Number of employees before creating
totemps = 0 Instances:", Employee.totemps)
payhike= 1.04 emp_1 = Employee('Rishi',70000)
def __init__(self,name,pay): emp_2 = Employee('Shwetha',80000)
self.name= name print("Number of employees after creating
self.pay = pay Instances:",Employee.totemps)
Employee. totemps +=1 print ("Pay of Employee 1:",emp_1.pay)
def apply_hike(self): print ("Pay of Employee 2:",emp_2.pay)
self.pay = int(self.pay * emp_1.apply_hike ()
Employee.payhike) emp_2.apply_hike()
print ("Pay of Employee 1 after hike:",emp_1.pay)
print ("Pay of Employee 1 after hike:",emp_2.pay)
Output
Number of employees before creating Instances: 0
Number of employees after creating Instances: 2
Pay of Employee 1: 70000
Pay of Employee 2: 80000
Pay of Employee 1 after hike: 72800
Pay of Employee 1 after hike: 83200 11
Namespaces
• Represents a memory block where names are mapped (or linked)
to objects
• A class maintains its own namespace, called ‘class namespace’
• In class namespace, the names are mapped to class variables.
• Every instance will have its own name space, called ‘instance
namespace’
• In instance namespace, the names are mapped to instance
variables.
12
Example - Namespace
class Student: Class Namespace
mks=10 mks 10
print(Student.mks)
Student.mks+=5
print(Student.mks)
s1=Student()
print(s1.mks) mks 10 mks 10
s2=Student() Instance Namespace of S1 Instance Namespace of S2
print(s2.mks)
Class Namespace
mks 15
mks 15 mks 15
s1=Student()
s1.mks+=5
print(s1.mks)
s2=Student()
mks 10 mks 10
print(s2.mks)
print(Student.mks) Instance Namespace of S1 Instance Namespace of S2
Class Namespace
mks 10
mks 15 mks 10
15
s1=Student()
15
s1.mks+=5 20
print(s1.mks) 20
Student.mks=20
print(s1.mks)
s2=Student()
print(s2.mks)
print(Student.mks)
15
class Sample:
x = 10
@classmethod x in S1= 10
def modify(cls): x in S2= 10
cls.x+=1 x in S1= 11
x in s2= 11
s1 = Sample() x in S1 after modification= 16
s2 = Sample() x in S2= 11
print('x in S1= ',s1.x) x in S2= 20
print('x in S2= ',s2.x) x in s2 after modification= 25
s1.modify() x Value= 20
print('x in S1= ',s1.x) x Value= 21
print('x in s2= ',s2.x) x value= 16
s1.x+=5
print('x in S1 after modification= ',s1.x)
print('x in S2= ',s2.x)
Sample.x=20
print('x in S2= ',s2.x)
s2.x=25
print('x in s2 after modification= ',s2.x)
print('x Value= ',Sample.x)
s2.modify()
print('x Value= ',Sample.x)
print('x value= ',s1.x) 16
Types of Methods
• Instance Methods
a. Accessor methods
b. Mutator methods
• Class Methods
• Static Methods
17
Instance Methods
Methods acting on Instance Variables.
Example:
class Rectangle():
def __init__(self, l, w): # self refers to the memory address of the instance
self.length = l # instance variable length
self.width = w # instance variable width
18
Accessor and Mutator methods
Example:
class Rectangle():
# mutator method
def setsides(self, l, w): # Not just read the variables, but also modify them
self.length = l
self.width = w
# accessor method
def getsides(self): # simply access or read data of variables
return self.length
return self.width
newRectangle = Rectangle()
newRectangle.setsides(12, 10)
print(newRectangle.getsides())
19
Class Methods
class Sample:
x = 10
s1 = Sample()
s2 = Sample()
print('x in S1= ',s1.x)
print('x in S2= ',s2.x)
s1.modify()
print('x in S1= ',s1.x)
print('x in S2= ',s2.x)
print('x Value= ',Sample.x)
20
Static Methods
• Static methods in Python are extremely similar to python class level methods,
the difference being that a static method is bound to a class rather than the
objects for that class.
• This means that a static method can be called without an object for that class.
• This also means that static methods cannot modify the state of an object as
they are not bound to it.
• Generally used as a utility method
Example
class Calculator:
# create addNumbers static method
@staticmethod
def multiplyNums(x, y):
return x * y
21
Write a program that counts the number of instances created
for a class
#understanding static methods
#Counting the number of objects created for a class
class MyClass:
n = 0 #this is a class variable or static variable
ob1 = MyClass()
ob2 = MyClass()
MyClass.noObjects()
22
Write a program to accept and display the following details of an
Employee:
Id, Name, Gender, Age, Designation, Date of Joining, Basic Salary
23
Passing Members of One class to Another Class
class Emp:
def __init__(self,id,name,salary): Output
self.id = id Id= 101
self.name = name Name= Hari
self.salary = salary Salary= 51000
Id= 103
def display(self): Name= John
print('Id= ',self.id) Salary= 21000
print('Name= ',self.name)
print('Salary= ',self.salary)
class UpdateSal:
@staticmethod
def incsalary(e):
e.salary+=1000
e.display()
e1=Emp(101,'Hari', 50000)
UpdateSal.incsalary(e1)
e2=Emp(103,'John',20000)
24
UpdateSal.incsalary(e2)
Inner Classes
#Inner Classes
class Person: Output
def __init__(self): Name= John
self.name ='John'
Date of Birth = 10/12/2000
self.db = self.DoB() #this is DoB object
2000
def display(self):
print('Name= ',self.name)
class DoB:
def __init__(self):
self.dd =10
self.mm =12
self.yy =2000
def display(self):
print('Date of Birth = {}/{}/{}'.format(self.dd,self.mm,self.yy))
class DoB:
def __init__(self):
self.dd =10
self.mm =12
self.yy =2000
def display(self):
print('Date of Birth = {}/{}/{}'.format(self.dd,self.mm,self.yy))
def show(self):
print(self.name,self.rollno)
s1 = Student('Ram',21)
s1.show()
lap1 =s1.Laptop('Dell','i3')
lap1.show() 27
Reusable modules
class Teacher:
def setid(self, id):
self.id = id
def getid(self): teacher.py
return self.id
Output
Id= 10
Name= John
Address= 18, I street, Bangalore
Salary= 50000
29
Reusable modules
class Student: student.py from student import Student
def setid(self, id): s = Student()
self.id = id s.setid(15)
def getid(self): s.setname('James')
return self.id s.setaddress('10, III street, Bangalore')
s.setmarks(85)
def setname(self, name):
self.name = name print('Id= ', s.getid())
def getname(self): print('Name= ', s.getname())
return self.name print('Address= ',s.getaddress())
print('Marks= ',s.getmarks())
def setaddress(self, address):
self.address = address
def getaddress(self):
return self.address
31
Constructors in Inheritance
# Constructor in Inheritance
class Father:
def __init__(self):
self.asset = 1000000
def display_asset(self):
print('Father\'s asset = ', self.asset)
class Son(Father):
pass
s= Son()
s.display_asset()
Output
Father's asset = 1000000
32
Overriding Super Class Constructors and Methods
# Overriding the base class constructor and method in sub class
class Father:
Output
def __init__(self): Son's asset = 2000000
self.asset = 1000000
def display_asset(self):
print('Father\'s asset = ', self.asset)
class Son(Father):
def __init__(self):
self.asset = 2000000
def display_asset(self):
print('Son\'s asset = ', self.asset)
s=Son()
s.display_asset()
33
The super() Method
# Accessing the base class constructor and method in sub class
class Father:
def __init__(self, asset=0): Output
self.asset = asset Total asset of Son = 3000000
def display_asset(self):
print('Father\'s asset = ', self.asset)
class Son(Father):
def __init__(self, asset1=0, asset=0):
super().__init__(asset)
self.asset1 = asset1
def display_asset(self):
print('Total asset of Son = ', self.asset1+self.asset)
s= Son(2000000, 1000000)
s.display_asset()
34
The super() method
35
The super() Method
# Accessing the base class constructor and method in sub class
class Father:
def __init__(self, asset=0): Output
self.asset = asset Total asset of Son = 3000000
def display_asset(self): Father's asset = 1000000
print('Father\'s asset = ', self.asset)
class Son(Father):
def __init__(self, asset1=0, asset=0):
super().__init__(asset)
self.asset1 = asset1
def display_asset(self):
print('Total asset of Son = ', self.asset1+self.asset)
super().display_asset()
s= Son(2000000, 1000000)
s.display_asset()
36
A Python program to access base constructor and methods in the sub
class using super()
class Square: Output
def __init__(self, x): Enter two measurements: 4 5
self.x =x Area of square= 16.0
def area(self): Area of rectangle= 20.0
print('Area of square= ', self.x *self.x)
class Rectangle(Square):
def __init__(self,x,y):
super().__init__(x)
self.y = y
def area(self):
super().area()
print('Area of rectangle= ',self.x * self.y)
class XYZBank(Bank):
pass
class ABCBank(Bank):
cash = 200000000
@classmethod
def available_cash(cls):
print(cls.cash + Bank.cash)
a = XYZBank()
a.available_cash()
b = ABCBank()
38
b.available_cash()
Multiple Inheritance
class subclass(BaseClass1, BaseClass2,….):
39
Multiple Inheritance
# Deriving a sub class from multiple base classes
class Bowler: Output
def print(self): I am a Bowler
I am a Batsman
print('I am a Bowler')
class Batsman:
def display(self):
print('I am a Batsman')
class AllRounder(Bowler,Batsman):
pass
player =AllRounder()
player.print()
player.display()
40
Create a class called Leader. Derive this class from the
base classes Person and Employee.
The attributes of Person class are name and idnumber.
The attributes of Employee class are salary and post.
41
Multiple Inheritance
# first parent class
class Person:
def __init__(self, name, idnumber):
self.name = name
self.idnumber = idnumber
print('Name: ',name, ' Idnumber: ',idnumber)
42
# inheritance from both the parent classes
class Leader(Person, Employee):
def __init__(self, name, idnumber, salary, post, votes):
self.votes = votes
Person.__init__(self,name,idnumber)
Employee.__init__(self,salary,post)
print('Votes: ',votes)
Output
Name: Rahul Idnumber: 12467
Salary: 75000 Post: General Manager
Votes: 60
43
Problems in Multiple Inheritance
# When super class have constructors
class A(object): Output
def __init__(self): c
self.a = 'a' a
print(self.a)
class B(object):
def __init__(self):
self.b = 'b'
print(self.b)
class B(object):
def __init__(self):
self.b = 'b'
print(self.b)
45
Problems in Multiple Inheritance
class A(object):
def __init__(self): Output
self.a ='a'
c
print(self.a)
a
super().__init__()
b
class B(object):
def __init__(self):
self.b ='b'
print(self.b)
super().__init__()
obj=C() 46
Method Resolution Order
Method Resolution Order defines the order in which the base classes
are searched when executing a method.
Object
2 3
47
Method Resolution Order(MRO)
1. Search for the sub class before going for its
base classes.
2. When a class is inherited from several
classes, it searches in the order from left to
right in the base classes.
3. It will not visit any class more than once.
48
Example
class A:
def process(self): Object
print('A process()')
class B(A):
pass
class C(A):
def process(self):
print('C process()')
class D(B,C):
pass C process()
51
Duck typing philosophy
If it looks like a duck, swims like a duck, and quacks like a duck, then it
probably is a duck.
By analogy, for computing languages, the type of an object is not important so
long as it behaves as expected
52
Duck typing philosophy - Example
# duck typing example
class Duck: Ouput
def talk(self): Quack Quack
print('Quack Quack') Hello
class Human:
def talk(self):
print('Hello')
def call_talk(obj):
obj.talk()
x= Duck()
call_talk(x)
x= Human()
call_talk(x)
53
# duck typing example
class Dog:
def bark(self): def call_talk(obj)
print('Bow') if hasattr(obj, 'talk'):
obj.talk()
class Duck: elif hasattr(obj, 'bark'):
def talk(self): obj.bark()
print('Quak Quak')
class Human:
def talk(self):
print('Hello')
def call_talk(obj)
obj.talk()
x= Duck()
call_talk(x)
x= Human()
call_talk(x)
x=Dog()
call_talk(x) #Attribute Error occurs in this call 54
Operator Overloading
• When an operator can perform different actions, it is said to exhibit
polymorphism.
• If any operator performs additional actions other than what it is
meant for, it is called Operator Overloading
Example
# Overloading the + operator
print(10+100)
s1 = 'News'
s2= 'Paper' 110
print(s1+s2) NewsPaper
[10, 49, 60, 35, -50, 20]
a = [10,49,60]
b = [35,-50,20]
print(a+b)
55
# using + operator on objects
class Bookx:
def __init__(self, pages): a + b ⇒ a. __add__(b)
self.pages = pages
class Booky:
def __init__(self, pages):
self.pages = pages
b1 = Bookx(100)
b2 = Booky(200)
print('Total pages = ', b1 + b2)
56
Magic Methods
Operator Method
+ object.__add__(self, other)
- object.__sub__(self, other)
* object.__mul__(self, other)
// object.__floordiv__(self, other)
/ object.__truediv__(self, other)
% object.__mod__(self, other)
** object.__pow__(self, other[, modulo])
<< object.__lshift__(self, other)
>> object.__rshift__(self, other)
& object.__and__(self, other)
^ object.__xor__(self, other)
| object.__or__(self, other)
57
Magic Methods
Operator Method
+= object.__iadd__(self, other)
-= object.__isub__(self, other)
*= object.__imul__(self, other)
/= object.__idiv__(self, other)
//= object.__ifloordiv__(self, other)
%= object.__imod__(self, other)
**= object.__ipow__(self, other[, modulo])
<<= object.__ilshift__(self, other)
>>= object.__irshift__(self, other)
&= object.__iand__(self, other)
^= object.__ixor__(self, other)
|= object.__ior__(self, other)
58
Magic Methods
Operator Method
- object.__neg__(self)
+ object.__pos__(self)
abs() object.__abs__(self)
~ object.__invert__(self)
complex() object.__complex__(self)
int() object.__int__(self)
long() object.__long__(self)
float() object.__float__(self)
oct() object.__oct__(self)
hex() object.__hex__(self
59
Magic Methods
Operator Method
< object.__lt__(self, other)
<= object.__le__(self, other)
== object.__eq__(self, other)
!= object.__ne__(self, other)
>= object.__ge__(self, other)
> object.__gt__(self, other)
60
# using > operator on objects
class Bookx:
def __init__(self, pages):
self.pages = pages
class Booky:
def __init__(self, pages):
self.pages = pages
b1 = Bookx(100)
b2 = Booky(200)
if (b1>b2):
print(' Bookx has more pages')
else:
print(' Booky has more pages')
61
import math
class Circle:
def __init__(self,radius):
self.radius = radius
def __add__(self,another_circle):
return Circle(self.radius + another_circle.radius)
def getRadius(self):
return self.radius
c1 = Circle(4)
print(c1.getRadius())
c2 = Circle(5)
print(c2.getRadius())
c3 = c1 + c2
# This became possible because we have overloaded + operator by
adding a method named __add__
print(c3.getRadius()) 62
Method Overloading
A method is written such that it can perform more than one task, is called
method overloading.
Writing more than one method with the same name is not possible in
Python.
63
# method overloading
class Myclass:
def sum(self, a = None, b=None, c=None):
if a!=None and b!=None and c!= None:
print('Sum of three = ',a+b+c)
elif a!=None and b!=None:
print('Sum of two = ',a+b)
else:
print('Please enter two or three arguments')
class Square(Rectangle):
def __init__(self,side):
self.side = side
Rectangle.__init__(self,side,side)
def getArea(self):
print (self.side*self.side," is area of square")
s = Square(4)
r = Rectangle(2,4)
s.getArea()
r.getArea()
65
Abstract classes and Interfaces
Abstract method is a method whose action is redefined in the sub classes
as per the requirement of the objects.
Generally abstract methods are written without body since their body will
be defined in the sub classes.
But, it is possible to write an abstract method with body also.
The decorator @abstractmethod is used to mark a method as abstract.
66
#abstract class example class Sub2(Myclass):
#Abstract Base Class def calculate(self,x):
from abc import ABC, abstractmethod print('Square root ',math.sqrt(x))
# or from abc import *
import math class Sub3(Myclass):
def calculate(self,x):
class Myclass(ABC): print('Cube value ',x**3)
@abstractmethod
def calculate(self,x): obj1= Sub1()
pass obj1.calculate(5)
obj2= Sub2()
#This is a subclass of Myclass obj2.calculate(36)
class Sub1(Myclass): obj3= Sub3()
def calculate(self,x): obj3.calculate(3)
print('Square value ',x*x)
67
Interfaces
An interface is an abstract class but it contains only abstract methods.
None of the methods in the interface will have body.
Only method headers will be written in the interface.
Interface can be defined as a specification of method headers
68
Program to develop an interface that connects to any database
# Abstract class works like an interface #This is another subclass
from abc import * class Sybase(Myclass):
class Myclass(ABC): def connect(self):
@abstractmethod print('Connecting to Sybase database')
def connect(self): def disconnect(self):
pass print('Disconnected from Sybase')
@abstractmethod
def disconnect(self): class Database:
pass str = input('Enter database name: ')
print(globals()[str])
#This is a subclass
class Oracle(Myclass): classname = globals()[str]
def connect(self):
print('Connecting to Oracle database') x=classname()
def disconnect(self): x.connect()
print('Disconnected from Oracle') x.disconnect()
Written when there are some Written when all the features are
common features shared by all implemented differently by
the objects different objects
When an interface is written any
third party vendor can provide
sub classes.
70
Write a program to find the area of
i) Square
ii) Regular Pentagon
iii) Regular hexagon
(Note: Use Abstract class with an abstract method by name area)
71