PYTHON
LECTURE 44
Today’s Agenda
• Advance Concepts Of Object Oriented
Programming-II
• Inheritance
• Types Of Inheritance
• Single Inheritance
• Using super( )
• Method Overriding
Inheritance
Inheritance is a powerful feature in object oriented
programming.
It refers to defining a new class with little or no
modification to an existing class.
The new class is called derived (or child) class and the
one from which it inherits is called the base (or parent)
class.
Real Life Examples
Real Life Examples
Benefits
It represents real-world relationships well.
It provides reusability of a code. We don’t have to write
the same code again and again.
It also allows us to add more features to a class without
modifying it.
Types Of Inheritance
Supported By Python
Syntax Of Single Inheritance
In Python
class BaseClass:
Body of base class
class DerivedClass(BaseClass):
Body of derived class
For Ex:
class Account:
pass
class SavingAccount(Account):
pass
Example
class Animal: duck=Bird()
duck.set_type("Duck")
def eat(self):
print(duck)
print("It eats.") duck.eat()
def sleep(self): duck.sleep()
print("It sleeps.") duck.fly()
duck.speak("Quack")
class Bird(Animal):
Output:
def set_type(self,type):
self.type=type
def fly(self):
print("It flies in the sky.")
def speak(self,sound):
print(f"It speaks:{sound},{sound}")
def __repr__(self):
return "This is a "+self.type;
Using super()
In Python , to call parent class members from the child
class we can use the method super( ).
Using super() is required in 2 situations:
For calling parent class constructor
For calling overridden methods
How Constructors Behave
In Inheritance ?
Whenever we create a child class object , Python looks
for __init__() method in child class.
If the child class doesn’t contain an __init__() method
then Python goes up in the inheritance chain and looks for
the __init__() method of parent class
How Constructors Behave
In Inheritance ?
If the parent class contains __init__() , then it execute it .
Now an important point to notice is that if child class
also has __init__() , then Python will not call parent’s
__init__() method.
That is , unlike Java or C++ , Python does not
automatically call the parent class __init__() if it finds an
__init__() method in child class
How Constructors Behave
In Inheritance ?
class A:
def __init__(self):
print("Instantiating A...")
As you can see,
class B(A): Python called the
constructor of class
pass
A , since B class
doesn’t has any
b=B() constructor defined
Output:
How Constructors Behave
In Inheritance ?
class A:
def __init__(self):
print("Instantiating A...")
This time , Python
class B(A): did not call the
constructor of class
def __init__(self):
A as it found a
print("Instantiating B...") constructor in B
itself
b=B()
Output:
How Constructors Behave
In Inheritance ?
So , what is the problem if parent constructor
doesn’t get called ?
The problem is that , if parent class constructor doesn’t
get called then all the instance members it creates will
not be made available to child class
How Constructors Behave
In Inheritance ?
class Rectangle: Since , constructor of
def __init__(self): Rectangle was not
called , so the
self.l=10
expression self.l
self.b=20 produced exception
class Cuboid(Rectangle): because there is no
def __init__(self): attribute created by
self.h=30 the name of l
def volume(self):
print("Vol of cuboid is",self.l*self.b*self.h)
obj=Cuboid()
obj.volume()
Output:
How Can We Explicitly
Call __init__() Of
Parent Class ?
If we want to call the parent class __init__() , then we
will have 2 options:
Call it using the name of parent class explicitly
Call it using the method super()
Calling Parent Constructor
Using Name
class Rectangle:
def __init__(self): Notice that we have
to explicitly pass the
self.l=10
argument self while
self.b=20 calling __init__()
method of parent
class Cuboid(Rectangle): class
def __init__(self):
Rectangle.__init__(self)
self.h=30
def volume(self):
print("Vol of cuboid is",self.l*self.b*self.h)
obj=Cuboid()
obj.volume()
Output:
Calling Parent Constructor
Using super( )
class Rectangle: Again notice that this
def __init__(self): time we don’t have to
self.l=10 pass the argument
self.b=20 self when we are
using super( ) as
Python will
class Cuboid(Rectangle):
automatically pass it
def __init__(self):
super().__init__();
self.h=30
def volume(self):
print("Vol of cuboid is",self.l*self.b*self.h)
obj=Cuboid()
obj.volume()
Output:
What Really Is super( ) ?
The method super() is a special method made available
by Python which returns a proxy object that delegates
method calls to a parent class
In simple words the method super( ) provides us a special
object that can be used to transfer call to parent class
methods
Benefits Of super( )
A common question that arises in our mind is that why to use super( )
, if we can call the parent class methods using parent class name.
The answer is that super( ) gives 4 benefits:
We don’t have to pass self while calling any method using super( ).
If the name of parent class changes after inheritance then we will not have to
rewrite the code in child as super( ) will automatically connect itself to current
parent
It can be used to resolve method overriding
It is very helpful in multiple inheritance
Method Overriding
To understand Method Overriding , try to figure out the
output of the code given in the next slide
Guess The Output ?
class Person:
def __init__(self,age,name):
self.age=age
self.name=name
def __repr__(self):
return f"Age:{self.age},Name:{self.name}"
class Emp(Person):
def __init__(self,age,name,id,sal):
super().__init__(age,name)
self.id=id
self.sal=sal
e=Emp(24,"Nitin",101,45000)
print(e)
Output:
Explanation
As we know , whenever we pass the name of an object
reference as argument to the function print( ) ,
Python calls the method __repr__().
But since the class Emp doesn’t has this method , so
Python moves up in the inheritance chain to find this
method in the base class Person
Now since the class Person has this method , Python calls
the __repr__() method of Person which returns only
the name and age
Method Overriding
Now if we want to change this behavior and show all 4
attributes of the Employee i.e. his name , age ,id and
salary, then we will have to redefine the method
__repr__() in our Emp class.
This is called Method Overriding
Thus , Method Overriding is a concept in OOP which
occurs whenever a derived class redefines the same
method as inherited from the base class
Modified Example
class Person:
def __init__(self,age,name):
self.age=age
self.name=name
def __repr__(self):
return f"Age:{self.age},Name:{self.name}"
class Emp(Person):
def __init__(self,age,name,id,sal):
super().__init__(age,name)
self.id=id
self.sal=sal
def __repr__(self):
return f"Age:{self.age},Name:{self.name},Id:{self.id},Salary:{self.sal}"
e=Emp(24,"Nitin",101,45000)
print(e)
Output:
Role Of super( )
In Method Overriding
When we override a method of base class in the
derived class then Python will always call the derive’s
version of the method.
But in some cases we also want to call the base class
version of the overridden method.
In this case we can call the base class version of the
method from the derive class using the function super( )
Syntax:
super( ). <method_name>(<arg>)
Modified Example
class Person:
def __init__(self,age,name):
self.age=age
self.name=name
def __repr__(self):
return f"Age:{self.age},Name:{self.name}"
class Emp(Person):
def __init__(self,age,name,id,sal):
super().__init__(age,name)
self.id=id
self.sal=sal
def __repr__(self):
str=super().__repr__()
return f"{str},Id:{self.id},Salary:{self.sal}"
e=Emp(24,"Nitin",101,45000)
print(e)
Output:
Exercise
Write a program to create a class called Circle having an instance member called radius.
Provide following methods in Circle class
__init___() : This method should accept an argument and initialize radius with it
area(): This method should calculate and return Circle’s area
Now create a derived class of Circle called Cylinder having an instance member called
height. Provide following methods in Cylinder class
__init___() : This method should initialize instance members radius and height with the
parameter passed.
area( ): This method should override Circle’s area( ) to calculate and return area of Cylinder .
( formula: 2πr2+2πrh)
volume(): This method should calculate and return Cylinder’s volume(formula: πr2h)
Solution
import math obj=Cylinder(10,20)
class Circle: print("Area of cylinder is",obj.area())
def __init__(self,radius): print("Volume of cylinder is",obj.volume())
self.radius=radius
def area(self):
return math.pi*math.pow(self.radius,2)
class Cylinder(Circle):
def __init__(self,radius,height):
super().__init__(radius)
self.height=height
def area(self):
return 2*super().area()+2*math.pi*self.radius*self.height
def volume(self):
return super().area()*self.height
Output:
A Very Important Point!
Can we call the base class version of an overridden
method from outside the derived class ?
For example , in the previous code we want to call the
method area( ) of Circle class from our main script .
How can we do this ?
Yes this is possible and for this Python provides us a
special syntax:
Syntax:
<base_class_name>.<method_name>(<der_obj>)
Example
import math obj=Cylinder(10,20)
class Circle: print("Area of cylinder is",obj.area())
def __init__(self,radius): print("Volume of cylinder is",obj.volume())
print("Area of Circle:",Circle.area(obj))
self.radius=radius
def area(self):
return math.pi*math.pow(self.radius,2)
class Cylinder(Circle): By calling in this way
def __init__(self,radius,height): we can bypass the
area( ) method of
super().__init__(radius)
Cylinder and directly
self.height=height call area( ) method
def area(self): of Circle
return 2*super().area()+2*math.pi*self.radius*self.height
def volume(self):
return super().area()*self.height
Output: