3.13 inheritance
Contents
Note
Click here to download the full example code or to run this example in your browser via Binder
3.13 inheritance#
Inheritance means one class can inherit attributes
and methods
of parent class.
class Human(object):
def __init__(self, name):
self.name = name
def say_salam(self):
print('Salam, my name is', self.name)
class Muslim(Human):
pass
ali = Muslim('Ali')
ali.say_salam()
Salam, my name is Ali
The Muslim
class itself does not have a method say_salam
but since
it is inheriting from Human
class and say_slam
exists in Human
class, we do end up calling say_salam
method fo Human
class.
We can check the type of the ali
which is an object and is an instance
of class Muslim
. There are two ways to verify this.
isinstance(ali, Muslim), type(ali) == Muslim
(True, True)
However, isinstance
checks the parent classes as well but type
function does not do so.
isinstance(ali, Human), type(ali) == Human
(True, False)
arjun = Human('arjun')
isinstance(arjun, Human), isinstance(arjun, Muslim)
(True, False)
So it is always safe to check the type of an object by instance
.
Inheritance can occur between more than two classes as well. In following, Pakistani
class inherits from Muslim class which itself inherits from Human
class.
class Human(object):
def __init__(self, name):
self.name = name
class Muslim(Human):
pass
class Pakistani(Muslim):
pass
ali = Pakistani('ali')
isinstance(ali, Human)
True
We can override the methods of parent or super class in its child class by
simply redefining the method
.
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
def introduction(self):
print('Salam, my name is', self.name)
ali = Muslim("ali")
ali.introduction()
Salam, my name is ali
Human.introduction(ali)
Hello, my name is ali
If in a child class we want to call/use method from a parent/super class, we can call method from parent/super class using the super() function as following.
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
def introduction(self):
print("I will call introduction method of parent class")
super().introduction()
ali = Muslim("ali")
ali.introduction()
I will call introduction method of parent class
Hello, my name is ali
Above, the introduction
method of Muslim
class calls the introduction
method of Human
.
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
def introduction(self):
print("salam: my name is ", self.name)
class Pakistani(Muslim):
def introduction(self):
print("I will call introduction method of parent class")
super().introduction()
ali = Pakistani("ali")
ali.introduction()
I will call introduction method of parent class
salam: my name is ali
If a method is not present in super / parent class , python will keep on looking in all parent / super classes in the hierarchy until it finds the method or attribute being called.
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
pass
class Pakistani(Muslim):
def introduction(self):
print("I will call introduction method of parent class")
super().introduction()
ali = Pakistani("ali")
ali.introduction()
I will call introduction method of parent class
Hello, my name is ali
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
pass
class Pakistani(Muslim):
pass
ali = Pakistani("ali")
ali.introduction()
Hello, my name is ali
However, if the called method does not exist in any of the parent classes, then python
will throw AttributeError
.
class Human(object):
def __init__(self, name):
self.name = name
def introduction1(self):
print('Hello, my name is', self.name)
class Muslim(Human):
pass
class Pakistani(Muslim):
pass
ali = Pakistani("ali")
# uncomment following line
# ali.introduction() # AttributeError
If in a child class , we want to implement a method of a parent class but not of immediate parent class, we can directly call that method.
Below, Pakistani
class is inheriting from Muslim
but in introduction method of
Pakistani
, we don’t want to call introduction
method of Muslim
class rather we
want to call introduction
method of Human
class.We can do this by Human.introduction()
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
def introduction(self):
print('Salam, my name is', self.name)
class Pakistani(Muslim):
def introduction(self):
Human.introduction(self)
print("I am a Pakistani. ")
ali = Pakistani("ali")
ali.introduction()
Hello, my name is ali
I am a Pakistani.
One of the function of method overriding is to implement abstract methods.
class Human(object):
def nationality(self):
raise NotImplementedError("implement this method in child class")
class Pakistani(Human):
def nationality(self):
return "pakistani"
class Iranian(Human):
def nationality(self):
return "iranian"
class Israili(Human):
pass
ali = Pakistani()
ali.nationality()
'pakistani'
armaghan = Iranian()
armaghan.nationality()
'iranian'
yakov = Israili()
# uncomment following line
# yakov.nationality() # NotImplementedError
We can enlist all base classes in a hierarchy of given class.
class Human(object):
pass
class Muslim(Human):
pass
class Pakistani(Human):
pass
class Punjabi(Pakistani):
pass
print(Punjabi.__mro__)
(<class '__main__.Punjabi'>, <class '__main__.Pakistani'>, <class '__main__.Human'>, <class 'object'>)
print(Muslim.__mro__)
(<class '__main__.Muslim'>, <class '__main__.Human'>, <class 'object'>)
We can initiate a child class with additional arguments than required to initiate the
parent class. For this we have to overwrite __init__()
method of the child class.
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
def __init__(self, name, sect):
self.sect = sect
super(Muslim, self).__init__(name)
def introduction(self):
print('Salam, my name is {} and my sect is {}'.format(self.name, self.sect))
# Uncomment following line
# ali = Muslim("ali") # TypeError
Above, the Muslim
class now requires two arguments for initiation i.e. name`
and sect. We did not provide value for sect
.
ali = Muslim("ali", None)
ali.introduction()
Salam, my name is ali and my sect is None
Instead of using super(ChildClass, self).__init__()
we can also simple say super().__init__()
.
class Human(object):
def __init__(self, name):
self.name = name
def introduction(self):
print('Hello, my name is', self.name)
class Muslim(Human):
def __init__(self, name, sect):
self.sect = sect
super().__init__(name)
def introduction(self):
print('Salam, my name is {} and my sect is {}'.format(self.name, self.sect))
ali = Muslim("ali", None)
ali.introduction()
Salam, my name is ali and my sect is None
type(ali.sect)
kapil = Human('kapil')
# uncomment following line
# kapil.sect # AttributeError
Since kapil
is an instance of Human
class which does not have any attribute named
sect
, thus we could not access this attribute.
multiple-inheritance#
A class can also inherit from multiple classes and this is called multiple-inheritance
.
class Spirit(object):
chastity = 'NaN'
bravery = 'NaN'
tolerance = 'NaN'
class Body(object):
weight = 20
class Human(Spirit, Body):
pass
ali = Human()
print(ali.chastity)
NaN
print(ali.weight)
20
If an attribute of the child class is called, it is first looked in the child class, then in the first parent class and then in second parent class.
class Spirit(object):
chastity = 'NaN'
bravery = 'NaN'
identity = 'NaN'
class Body(object):
identity = 'name'
class Human(Spirit, Body):
pass
ali = Human()
print(ali.identity)
NaN
Above, identity
attribute exists for Body
and Spirit
class but
since Spirit
class comes first, so NaN
is printed which is value of
identity
attribute of Spirit
class. Sometimes, we may want to initialize
both parent classes with separate initializing arguments. In following, Body
class requires two initiating arguments while Spirit
class can be initialized
with as many arguments as possible.
class Spirit(object):
def __init__(self, **kwargs):
print("initializing spirit")
for k, v in kwargs.items():
print('setting: ', k, 'to ', v)
setattr(self, k, v)
print("finished initializing spirit")
class Body(object):
def __init__(self, weight, height):
print("initializing body")
self.weight = weight
self.height = height
print("finished initializing body")
class Human(Spirit, Body):
def __init__(self, name, weight, height, **kwargs):
print("initializing Human")
self.name = name
Spirit.__init__(self, **kwargs)
Body.__init__(self, weight, height)
ali = Human('ali', 60, 175, chastity='NotANumber')
print("Name: ", ali.name)
print("Weight: ", ali.weight)
print("Height: ", ali.height)
print("Chastity: ", ali.chastity)
initializing Human
initializing spirit
setting: chastity to NotANumber
finished initializing spirit
initializing body
finished initializing body
Name: ali
Weight: 60
Height: 175
Chastity: NotANumber
Instead of initializing both parent classes separately, call to super()
method
will suffice to initiate all parent classes at once.
class Spirit(object):
def __init__(self, **kwargs):
print("initializing spirit")
for k, v in kwargs.items():
print('setting: ', k, 'to ', v)
setattr(self, k, v)
print("finished initializing spirit")
class Body(object):
def __init__(self, weight, height):
print("initializing body")
self.weight = weight
self.height = height
print("finished initializing body")
class Human(Spirit, Body):
def __init__(self, name, weight, height, **kwargs):
print("initializing Human")
self.name = name
super().__init__(weight=weight, height=height, **kwargs)
ali = Human('ali', 60, 175, chastity='NotANumber', honesty="undefined")
print("Name: ", ali.name)
print("Weight: ", ali.weight)
print("Height: ", ali.height)
print("Chastity: ", ali.chastity)
initializing Human
initializing spirit
setting: weight to 60
setting: height to 175
setting: chastity to NotANumber
setting: honesty to undefined
finished initializing spirit
Name: ali
Weight: 60
Height: 175
Chastity: NotANumber
Total running time of the script: ( 0 minutes 0.015 seconds)