0% found this document useful (0 votes)
3 views

3.0 - Inheritance in Python

The document explains inheritance in Python, detailing how subclasses can inherit attributes and methods from superclasses, allowing for code reusability and abstraction. It covers the use of the super() function, method overriding, polymorphism, abstract classes, and multiple inheritance, providing examples for each concept. Additionally, it discusses the implications of using abstract base classes versus NotImplementedError for enforcing method implementation in subclasses.

Uploaded by

chakrasgt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

3.0 - Inheritance in Python

The document explains inheritance in Python, detailing how subclasses can inherit attributes and methods from superclasses, allowing for code reusability and abstraction. It covers the use of the super() function, method overriding, polymorphism, abstract classes, and multiple inheritance, providing examples for each concept. Additionally, it discusses the implications of using abstract base classes versus NotImplementedError for enforcing method implementation in subclasses.

Uploaded by

chakrasgt
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 41

Inheritance in Python

CC3 – Object Oriented Programming


Introducing Inheritance
• To recall what this term means, inheritance allows us to create
“is a” relationships between two or more classes.
• This allows us to abstract common logic into super-classes and
manage specific details in the subclass.
• The superclass is the “parent” that has all the methods and
attributes.
• The subclass is the “child” that inherits all the methods and
attributes of the superclass.
Introducing Inheritance
• A new class can be derived from an existing class as follows:
• class MyClass(object):
• pass
• In Python 2.2 and Python 3 onwards, all classes implicitly
inherit from the object class.
• This means we do not need to type object when defining the
parent class.
• This was just shown to demonstrate how Python tells classes
they can be inherited.
Introducing Inheritance
• A new class can be derived from an existing class as follows:
• class SuperClass(object):
• pass
• class SubClass(SuperClass):
• pass
• This syntax tells Python that the “SubClass” should be derived
from the “SuperClass”.
Using Inheritance
• Here is a simple example of how inheritance can be
implemented:
• class Cat:
• def __init__(self, breed, color):
• self.breed = breed
• self.fur_color = color
• def meow(self):
• print("The cat meows.")
Using Inheritance
• Here is a simple example of how inheritance can be
implemented:
• class PersianCat(Cat):
• pass

• persian_cat1 = PersianCat("Persian Cat", "White")


• print(persian_cat1.fur_color) # Outputs: White
• persian_cat1.meow() # Outputs: The cat meows.
Using Inheritance
• As seen in the previous example, the “PersianCat()” class
inherits the attributes and methods of the “Cat()” class.
• This also includes the “__init__” method, which means the child
class will also need to instantiate an object.
• When we would like to use the attributes in the “Cat()” class,
we simply need to call them.
• We do not need to define the same attributes and methods in
our child class “PersianCat()”.
The super() function
• The super function returns the object as an instance of the
parent class, which allows us to call the parent method directly.
• This essentially allows a child class to call all the methods of the
parent class.
• This is meant to allow code reusability.
• This allows you to override methods in your child class, but still
access the “original” methods in your parent class.
Using Inheritance
• We define a super class “Rectangle” with the following
attributes and behaviors:
• class Rectangle:
• def __init__(self, width, height):
• self.width = width
• self.height = height
• def area(self):
• return self.width * self.height
• def perimeter(self):
• return 2 * (self.width * self.height)
Using Inheritance
• We can now define a subclass “Square”.
• Since a square is simply a rectangle with equal sides, these two
shapes share characteristics and can then be inherited.
• Here is the source code example for the subclass “Square”:
• class Square(Rectangle):
• def __init__(self, side):
• super().__init__(side, side)
• self.side = side
Using Inheritance
• We use the “super()” method to allow us to set the sides of the
square with the help of the parent class.
• What is happening is we are asking the user to give a value for
the square when it is instantiated.
• We then pass that value as both the height and width to the
“Rectangle()” class initializer.
• This allows us to set the sides of the square to be equal.
Using Inheritance
• Once you have your superclass and subclass linked together,
you can then start creating objects for both classes.
• Keep in mind that objects created for either class are
independent of each other.
• Here are some examples of objects created along with their
outputs:
• rectangle_example = Rectangle(2, 3)
• print(rectangle_example.area()) # Outputs 6
• print(rectangle_example.perimeter()) # Outputs 12
Using Inheritance
• We can now also create objects for our “Square()” class by
passing only one value:
• square_example = Square(5)
• print(square_example.area()) # Outputs 25
• print(square_example.perimeter()) # Outputs 50
Overriding Class Behavior
Object Oriented Programming
Overriding Class Behavior
• Inheritance allows us not only to add new behavior to existing
classes but change behavior.
• Overriding means altering or replacing a method of the
superclass with a new method in the subclass.
Overriding Class Behavior
• When overriding methods, you are usually only overriding
methods of the same name.
• No special syntax is needed to do this.
• You simply need to recreate the method you would like to
override.
• The subclass’s newly created method is automatically called
instead of the superclass’s method.
Overriding Class Behavior
• Let us say we have a parent class named “Enemy()”:
• class Enemy:
• def __init__(self, hp, mp, attk, deff):
• self.hp = hp
• self.mp = mp
• self.attk = attk
• self.deff = deff
• def attack(self):
• print("The enemy swings their sword at
you!")
Overriding Class Behavior
• We can then have a “Dragon()” class inherit the methods of the
“Enemy()” class:
• class Dragon(Enemy):
• def attack(self):
• print("A dragon spits a massive ball of fire
at you!")

• dragon1 = Dragon(1000, 500, 250, 300)


• dragon1.attack() # A dragon spits a massive ball of
fire at you!
Polymorphism
Object Oriented Programming
Polymorphism
• If you recall, polymorphism is having different behaviors
happen depending on which subclass is being used.
• In this case, we don’t need to know what the subclass is.
• This, when paired with inheritance concepts, allows us to have
a single method or behavior with multiple uses and outputs.
• The simplest way to implement this is to modify the methods in
the child class inherited by the parent class.
Polymorphism
• As an example, let us have a parent class “Dog” with a method
“getDogCoat” and several child classes that inherit this method:
• class Dog:
• def introduceDog(self):
• print("The dog goes bark.")
• def getDogCoat(self):
• pass

• class YorkshireTerrier(Dog):
• def getDogCoat(self):
• print("The Yorkshire Terrier has a Long Dog
Coat.")
Polymorphism
• As an example, let us have a parent class “Dog” with a method
“getDogCoat” and several child classes that inherit this method:
• lass Dobermann(Dog):
• def getDogCoat(self):
• print("The Dobermann has a Short Dog Coat.")

• class Poodle(Dog):
• def getDogCoat(self):
• print("The Poddle has a Curly Coat.")
Polymorphism
• As an example, let us have a parent class “Dog” with a method
“getDogCoat” and several child classes that inherit this method:
• yk = YorkshireTerrier()
• yk.introduceDog() # Outputs: The dog goes bark.
• yk.getDogCoat() # Outputs: The Yorkshire Terrier has
a Long Dog Coat.

• db = Dobermann()
• db.introduceDog() # Outputs: The dog goes bark.
• db.getDogCoat() # Outputs: The Dobermann has a Short
Dog Coat.
Polymorphism
• As an example, let us have a parent class “Dog” with a method
“getDogCoat” and several child classes that inherit this method:
• p = Poodle()
• p.introduceDog() # Outputs: The dog goes bark.
• p.getDogCoat() # Outputs: The Poddle has a Curly
Coat.
Polymorphism
• As seen in the example, the “getDogCoat()” method is used by
multiple child classes of the “Dog” class.
• Despite the child classes all inheriting the “getDogCoat()”, they
overwrite with their own output.
• This allows the “getDogCoat()” to have different outputs
depending on which child classes implements it.
• Polymorphism makes use of concepts in overriding for it to
work.
Abstract Classes
Object Oriented Programming
Abstract Classes
• Abstract base classes (ABC), defines a set of methods and
properties that a class must implement.
• A class can extend an abstract base class itself in order to be
used as an instance of that class.
• In doing this, the class in question must supply all the
appropriate methods.
Creating Abstract Classes
• The first method of implementing abstract classes is quite
simple, we simply give an error if a class is not changed:
• class Fruit:
• def check_ripeness(self):
• raise NotImplementedError("check_ripeness
method not implemented!")

• class Apple(Fruit):
• pass
Creating Abstract Classes
• When we try to implement the class, we will get an error:
• apple1 = Apple()
• apple1.check_ripeness() # Gives a
"NotImplementedError: check_ripeness method not
implemented!"
• This informs the user or developer to implement the specified
class.
• While this encourages implementation of these classes, it does
not enforce their definition.
Creating Abstract Classes
• We can make use of the “abc” module, to enforce
implementation.
• This prevents child classes from being instantiated if they failed
to override abstract class methods:
• from abc import ABCMeta, abstractmethod

• class AbstractClass(metaclass = ABCMeta):


• @abstractmethod
• def required_method(self):
• pass
Creating Abstract Classes
• Now, if we try to have a subclass inherit our main class, it will
not work at all:
• class SubClass(AbstractClass):
• pass

• subclass1 = SubClass()
• subclass1.required_method() # Gives an Error when
Run
NotImplementedError() vs ABC
• You many be wondering why should we go through the trouble
of implementing ABC if both methods give an error.
• In the case of NotImplementedError(), this still allows us to
instantiate an object of an Abstract class without getting an
error.
• We will not get an error until we try to call the abstract
method/s in question.
NotImplementedError() vs ABC
• On the other hand, the ABC module stops us from instantiating
a class completely unless we override the abstract method.
• If we try to instantiate a child class, we will immediately get an
error.
• The error will occur regardless of whether we implement the
abstract methods or not.
Multiple Inheritance
Object Oriented Programming
Multiple Inheritance
• Multiple Inheritance is a case where a subclass that inherits
from multiple parent classes can access functionality from both.
• In practice, this is less useful than it sounds, and it is not
recommended to use this method.
• The simplest and most useful form of multiple inheritance is
called a mixin.
• A mixin is generally a superclass that is not meant to exist on its
own but is meant to be inherited to provide extra functions.
Multiple Inheritance in Diagram
Food
String: name
int: calories
Breakfast_Food beDigested()
Lunch_Food
int: servings
int: protein int: servings

beDigested() beDigested()

Brunch_Food
int: cost
beDigested()
• Breakfast_Food and Lunch_Food
inherit Food
• Brunch_Food inherits both
Breakfast_Food and Lunch_Food

• Output:
name is Food
protein count is 20
serving size is 1
cost is 10
Multiple Inheritance
• Let us say we have a contact list class called “Contacts”:
• class Contact:
• def __init__(self, name, email):
• self.name = name
• self.email = email
• # Other contact information
• def editContactInfo(self):
• # Editing contact information
• def delContactInfo(self):
• # Deleting contact information
Multiple Inheritance
• Next, let’s say we wanted to add some functionality to the
“Contact” class that allows sending an email to “self.email”.
• We can write a mixin class to do the e-mailing:
• class MailSender:
• def send_mail(self, message):
• print("Sending mail to " + self.mail)
• # Email code goes here
• This class doesn’t do anything special, but it allows us to define
a new class that describes both “Contact” and “MailSender”.
Multiple Inheritance
• We can now create a class that makes use of multiple
inheritance:
• class EmailableContact(Contact, MailSender):
• pass
• email = EmailableContact("John Doe",
"[email protected]")
• email.send_mail("Hello, this is a test email!")
Multiple Inheritance
• Just to emphasize that there are better methods to implement
this instead of multiple inheritance, here are some alternatives:
• You can use single inheritance and add the “send_mail” function to the
subclass.
• You can create a standalone Python function for sending an e-mail, and just
call that function with the correct e-email address.

You might also like