0% found this document useful (0 votes)
57 views18 pages

Step 1 1f Object Oriented Python

The document discusses object-oriented programming concepts like classes, objects, methods, and class vs instance variables in Python. It provides an example Robot class to demonstrate these concepts, including defining a class, initializing objects, using class and instance variables, and implementing methods like say_hi() and die() to define object behavior. The Robot class tracks a population count as a class variable to show how changes made by one object can affect others.

Uploaded by

Nitesh Tiwari
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
57 views18 pages

Step 1 1f Object Oriented Python

The document discusses object-oriented programming concepts like classes, objects, methods, and class vs instance variables in Python. It provides an example Robot class to demonstrate these concepts, including defining a class, initializing objects, using class and instance variables, and implementing methods like say_hi() and die() to define object behavior. The Robot class tracks a population count as a class variable to show how changes made by one object can affect others.

Uploaded by

Nitesh Tiwari
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 18

Objected Oriented Python Topics

Objects and Classes


Inheritance
Encapsulation
Abstract Classes
Interfaces

Object Oriented Programming is a paradigm of programming used to represent real-world objects in programs.

Real-world objects have certain properties and behaviours. These are modelled with Classes and Objects in
Python.

Properties or Data Fields capture the state of real-world objects and Methods capture the behavior of real-world
objects

Objects and Classes


Classes and Objects are the two main aspects of Object Oriented Programming (OOP)
A class creates a new type (remember data types?)
where objects are instances of the class type

Fig 1 - Instantiating

In [ ]:
# create an empty class called `Person`
# (NOTE: class names always begin with a capital letter!)
class Person:
pass # empty block

# Create object `p` from class `Person`


p = Person()

# Print `p`
print(p)

Attributes of a Class
(Data) Fields : Variables that belong to an object or class are referred to as fields
Objects can store data using ordinary variables that belong to the object
Methods: Objects can also have functionality by using functions that belong to a class
Such functions are called methods of the class

Collectively, the fields and methods can be referred to as the attributes of that class.
Fig 2a - Data Fields (Properties) and Methods

Fig 2b - Data Fields (Properties) and Methods


Methods

In [ ]:
# create a class called `Person`
class Person:
# create a new built in method called say_hi
def say_hi(self):
print('Hello, how are you?')

# instantiate object `p` from `Person` class


p = Person()

# run the built-in method from object `p`


p.say_hi()

Notice that the say_hi method takes no parameters when calling it in the object
but still has the self in the class function definition

self keyword

Class methods have only one specific difference from ordinary functions
they must have an extra first parameter that has to be added to the beginning of the parameter list
by convention, it is given the name self .
do not give a value for this parameter when you call the method
Python will automatically provide it
this particular variable refers to the object itself

Data Fields
we have already discussed the functionality part of classes and objects (i.e. methods),
now let us learn about the data part.
the data part, i.e. fields, are nothing but ordinary variables that are bound to the namespaces of the classes
and objects
recall scope of variables in functions, this works similar to that, but at class and object levels

__init__ method: the constructor function

There are many method names which have special significance in Python classes
We will see the significance of the __init__ method
The __init__ method is run as soon as an object of a class is instantiated (i.e. created)
The method is useful to do any initialization you want to do with your object
i.e. passing initial values to your object variables

In [ ]:
# create Class called `Person`
class Person:

# create the __init__ constructor function


def __init__(self,name):
self.name = name # object variable

# create method called say_hi


# this will be a built-in function for this class `Person`
def say_hi(self):
print('Hello, my name is ', self.name)

# instatiate an object `p` from class `Person`


# remember to input the `name` as Class argument
p = Person('Jill')
# call built-in method
p.say_hi()

The variables under the __init__ function have to be passed as arugments when creating the object from
the class
When creating new instance p , of the class Person
we do so by using the class name, followed by the arguments in the parentheses
We define the __init__ method as taking a parameter name
We do not explicitly call the init method, this is the special significance of this method
self.name means that there is something called "name" that is part of the object called "self"
the other name is a local variable

Class Variable vs. Object Variable


there are two types of data fields
class variables
object variables
these are classified depending on whether the class or the object owns the variables respectively

Fig 3 - Class vs. Object

class variable :

they can be accessed by all instances of that class


here is only one copy of the class variable and when any one object makes a change to a class variable
that change will be seen by all the other instances.

object variable :

are owned by each individual object/instance of the class


each object has its own copy of the field
they are not shared and are not related in any way to the field by the same name in a different instance

Robot Class Example


it is important to learn classes and objects with examples
so we will look at a Robot class example
We define a Robot class with the following attributes:
Class Variables:
population : keeps count of the number of objects instantiated from the class
Class Function:
how_many : returns the current number of robots
Properties:
name : object varible that hold the name of the current robot
Methods:
say_hi : robot says hi
say_hi : robot says hi
die : robot gets terminated and updates the number of total robots

ASIDE #1:
Docstrings :
these are string literals that appear right after the definition of a function, method, class, or module
they appear when help(function_name) is run

In [ ]:
# Docstrings Example

def is_even(num):
# Docstring
"""
Input: an integer
Output: if input is even (True for even, False for not)
"""
return num % 2 == 0

help(is_even)

ASIDE #2:
.format()
used to fill in the blanks of a string in the print() statement

In [ ]:
# `.format()` example

pi_value = 3.14
print("The value of Pi is {} ".format(pi_value))

Robot Class Setup

In [ ]:
# Define a class called Robot
class Robot:
"""Represents a robot, with a name.""" # Docstrings

# Class Variable: population


population = 0

# Constructor Function: __init__()


def __init__(self, name):
"""Initializes the data.""" # Docstrings
self.name = name # Object Variable
print("(Initializing {} )".format(self.name))

# When a new robot is created, the robot


# adds to the population
Robot.population += 1

# Object Method: die()


def die(self):
"""I am dying.""" # Docstrings
print("{} is being destroyed!".format(self.name))

Robot.population -= 1

if Robot.population == 0:
print("{} was the last one.".format(self.name))
else:
print("There are still {:d} robots working.".format(
Robot.population))

# Object Method: say_hi()


def say_hi(self):
"""Greeting by the robot.
Yeah, they can do that.""" # Docstrings
print("Greetings, my masters call me {} .".format(self.name))

# Class Method: how_many()


@classmethod
def how_many(cls):
"""Prints the current population.""" # Docstrings
print("We have {:d} robots.".format(cls.population))

Explanation of Robot Class Setup


object variables

the name variable belongs to the object (it is assigned using self ) and hence is an object variable
we refer to the object variable name using self.name notation in the methods of that object
NOTE: an object variable with the same name as a class variable will hide the class variable!
instead of Robot.population , we could have also used self.__class__.population because every
object refers to its class via the self.__class__ attribute

object methods

in the say_hi built-in object method, the robot outputs a greeting


in the die built-in object method, we simply decrease the Robot.population count by 1

docstrings

in this program, we see the use of docstrings for classes as well as methods
we can access the class docstring using Robot.__doc__ and the method docstring as
Robot.say_hi.__doc__

constructor function

observe that the __init__ method is used to initialize the Robot instance with a name
in this method, we increase the population count by 1 since we have one more robot being added
also observe that the values of self.name is specific to each object which indicates the nature of
object variables

class variable

population belongs to the Robot class


hence is a class variable
thus, we refer to the population class variable as Robot.population and not as self.population

class function

the how_many is actually a method that belongs to the class and not to the object
this means we can define it as either a classmethod or a staticmethod depending on whether we need
to know which class we are part of
since we refer to a class variable , let's use classmethod
we have marked the how_many method as a class method using a decorator
decorators can be imagined to be a shortcut to calling a wrapper function (i.e. a function that "wraps"
around another function so that it can do something before or after the inner function), so applying the
@classmethod decorator is the same as calling:

how_many = classmethod(how_many)

public vs. private attributes

all class members are public


all class members are public
One exception: if you use data members with names using the double underscore prefix such as
__privatevar , Python uses name-mangling to effectively make it a private variable.
the convention followed is that any variable that is to be used only within the class or object should begin
with an underscore and all other names are public and can be used by other classes/objects
remember that this is only a convention and is not enforced by Python (except for the double underscore
prefix)

In [ ]:
# Using the above Robot Class setup

#------------------------------------------------------
# Initialize Robot 1 called 'R2-D2' in `droid1`
droid1 = Robot("R2-D2")

# Call the Built-In Object Function for `droid1`


droid1.say_hi()

# Call the Class Function


Robot.how_many()

#------------------------------------------------------
# Initialize Robot 2 called 'C-3PO'
droid2 = Robot("C-3PO")

# Call the Built-In Object Function for droid2


droid2.say_hi()

# Call the Class Function


Robot.how_many()

#------------------------------------------------------
# Print a note about Robots working
print("\n Robots can do some work here.\n ")

# Print a note about destroying Robots


print("Robots have finished their work. So let's destroy them.")

#------------------------------------------------------
# Use Built-In Object Functions
droid1.die()
droid2.die()

# Call the Class Function


Robot.how_many()

Inheritance
a major benefit of OOP is reuse of code
one way this is achieved is through inheritance mechanism
inheritance can be best imagined as implementing a type (parent class) and subtype (child class)
relationship between classes
School Members Example

Problem Statement:
suppose you want to write a program for a college which has to keep track of
teachers
students
they both have some common characteristics such as
name,
age and
address
they also have specific characteristics such as
for teachers
salary
courses
leaves
for students
marks
fees

Solution Strategy:
independent classes

you can create two independent classes for each type ( teachers and students), but adding a new common
characteristic would mean adding to both of these independent classes
this quickly becomes unwieldy

inherited classes

a better way would be to create a common class called SchoolMember and then have the teacher and
student classes inherit from this class
i.e. they will become sub-types (child classes) of this type (parent class) and then we can add specific
characteristics to these sub-types
there are many advantages to this approach

1. if we add/change any functionality in SchoolMember , this is automatically reflected in the subtypes as


well
for example, you can add a new ID card field for both teachers and students by simply adding it to
the SchoolMember class
however, changes in one subtype (child class) does not affect other subtype (child class)
2. another advantage is that you can refer to a teacher or student object as a SchoolMember object
which could be useful in some situations such as counting of the number of school members
this is called polymorphism where a sub-type can be substituted in any situation where a parent
type is expected,
i.e. the object can be treated as an instance of the parent class.
3. also observe that we reuse the code of the parent class and we do not need to repeat it in the child
3. also observe that we reuse the code of the parent class and we do not need to repeat it in the child
classes as we would have had to in case we had used independent classes
the SchoolMember class in this situation is known as the base class , parent class or the superclass.
the Teacher and Student classes are called the derived classes , child class or subclasses

Implementing the Strategy:

Create a Parent Class


parent class called SchoolMember

In [ ]:
class SchoolMember :
'''Represents any school member.'''
def __init__(self, name, age):
self.name = name
self.age = age
print('(Initialized SchoolMember: {} )'.format(self.name))

def tell(self):
'''Tell my details.'''
print('Name:"{} " Age:"{} "'.format(self.name, self.age), end=" ")

Create a Child Class


child class TeacherClass from Parent SchoolMember

In [ ]:
class Teacher (SchoolMember):
'''Represents a teacher.'''
def __init__(self, name, age, salary):
SchoolMember.__init__(self, name, age)
self.salary = salary
print('(Initialized Teacher: {} )'.format(self.name))

def tell(self):
SchoolMember.tell(self)
print('Salary: "{:d}"'.format(self.salary))

Create a Child Class


child class StudentClass from Parent SchoolMember

In [ ]:
class Student (SchoolMember):
'''Represents a student.'''
def __init__(self, name, age, grade):
SchoolMember.__init__(self, name, age)
self.grade = grade
print('(Initialized Student: {} )'.format(self.name))

def tell(self):
SchoolMember.tell(self)
print('Grade: "{:d}"'.format(self.grade))

Initialize a new Teacher Object and Student Object

In [ ]:
# initialize `t` - teacher object
t = Teacher('Mrs. Alyssa', 40, 30000)
# name: Mrs. Alyssa
# age: 40
# salary: 30000

# prints a blank line


print()

# initialize `s` - student object


s = Student('Daniel', 25, 75)
# name: Daniel
# age: 25
# grade: 75

# prints a blank line


print()

members = [t, s]
for member in members:
# Works for both Teachers and Students
member.tell()

Explanation of Inheritance
to use inheritance, we specify the parent-class names in a tuple following the class name in the class
definition
for example, class Teacher(SchoolMember)
next, we observe that the __init__ method of the parent-class is explicitly called using the self variable
so that we can initialize the parent class part of an instance in the child-class
since we are defining a __init__ method in Teacher and Student subclasses, Python does not
automatically call the constructor of the child-class SchoolMember , you have to explicitly call it
yourself
in contrast, if we had not defined an __init__ method in the child-classes, Python will call the
constructor of the parent-class automatically
while we could treat instances of Teacher or Student as we would an instance of SchoolMember and
access the tell method of SchoolMember by simply typing Teacher.tell or Student.tell , we instead
define another tell method in each child-class (using the tell method of SchoolMember for part of it)
to tailor it for that subclass
because we have done this, when we write Teacher.tell , Python uses the tell method for that
child-class vs the parent-class
however, if we did not have a tell method in the child-class, Python would use the tell method in
the parent-class
Python always starts looking for methods in the actual child-class type first
and if it doesn’t find anything, it starts looking at the methods in the child-class's parent-classes,
one-by-one in the order they are specified in the tuple in the class definition
here we only have 1 base class, but you can have multiple parent classes
a note on terminology - if more than one class is listed in the inheritance tuple, then it is called multiple
inheritance
the end parameter is used in the print function in the parent-class's tell() method to print a line and
allow the next print to continue on the same line
this is a trick to make print not print a \n (newline) symbol at the end of the printing

Encapsulation
an object's variables should not always be directly accessible
to prevent accidental change, an object's variables can sometimes only be changed with an objects
methods
those type of variables are private variables
the methods can ensure the correct values are set
if an incorrect value is set, the method can return an error
Python does not have the private keyword, unlike some other object oriented languages, but encapsulation
can be done
to achieve this, it relies on the convention
a class variable that should not directly be accessed should be prefixed with an underscore

In [ ]:
## Encapsulation Example

# initialize a new class


class Robot:

# constructor function
def __init__(self):
self.a = 123 # public object variable
self._b = 123 # private object variable (by convention - not a hard variable)
self.__c = 123 # Python enforced private variable

# instantiate a new object


new_robot = Robot()

print(new_robot.a) # publicly accessible


print(new_robot._b) # publicly accessible, but private by convention
print(new_robot.__c) # Python enforced private variable, access throws error

an attempt to access the Python enforced private variable yields an error as seen above
single underscore :
Private variable, it should not be accessed directly. But nothing stops you from doing that (except
convention).
More specifically, a "protected" variable, if drawing parallels to other programming langauages
double underscore :
Private variable, harder to access but still possible.
Both are still accessible: Python only has private variables by convention.

Getters and Setters


private variables are intended to be changed using getter and setter methods
These provide indirect access to them

In [ ]:
# initialize a new Robot class
class Robot:

# constructor function
def __init__(self):
self.__version = 22

# getter function
def getVersion(self):
print(self.__version)

# setter function
def setVersion(self, version):
self.__version = version

# instantiate a new object called 'new_robot'


new_robot = Robot()

# use the getter function


new_robot.getVersion()

In [ ]:

# use the built in setter function


# use the built in setter function
new_robot.setVersion(23)

# use the getter function again


new_robot.getVersion()

In [ ]:

# but try accessing the private variable


print(new_robot.__version) # throws error

Encapsulation Boundaries
private properties do not extend to child classes, or the public object
protected properties extend to child classes, but not the public object
when overriding with functions in the child classes,
the access level can be same or weaker
not stronger
once the object is created
only public attributes and methods can be accessed

Abstract Classes
an abstract class can be considered as a blueprint for other classes
it allows you to create a set of methods that must be created within any child classes built from the parent
abstract class
a class which contains one or more abstract methods is called an abstract class.
an abstract method: a method that has a declaration but does not have an implementation
while we are designing large functional units we use an abstract class.
when we want to provide a common interface for different implementations of a component, we use an
abstract class

Why use Abstract Classes?


by defining an abstract parent class, you can define a common Application Program Interface (API) for a set
of subclasses (chidren classes)
this capability is especially useful in situations where a third-party is going to provide implementations, such
as with plugins, but can also help you when working in a large team or with a large code-base where
keeping all classes in your mind is difficult or not possible

Python and Abstract Classes


by default, Python does not provide abstract classes
Python comes with a module which provides the base for defining Abstract Base classes (ABC)
that module name is ABC
ABC works by decorating methods of the parent class as abstract and then registering concrete classes as
implementations of the abstract parent
A method becomes abstract when decorated with the keyword @abstractmethod

Abstract Class Example


define abstact class called Polygon
with an abstract method called noofsides
the abstract method forces this method to be defined again (overridden) in the children classes
then, define following children classes from the parent Polygon class
Triangle
Quadilateral
Pentagon
Hexagon
within each child class, the abstract method noofsides is overrideen with a custom method, but with the
same name

In [ ]:

# imported abstract base class

from abc import ABC, abstractmethod

# Parent Abstract Method ---------------------------------------------------


class Polygon (ABC):

# abstract method inside the parent Abstract Class


def noofsides(self):
pass

# Child Class #1 of Polygon Parent Abstract Class --------------------------


class Triangle(Polygon):

# overriding abstract method


def noofsides(self):
print("I have 3 sides")

# Child Class #2 of Polygon Parent Abstract Class --------------------------


class Pentagon(Polygon):

# overriding abstract method


def noofsides(self):
print("I have 5 sides")

# Child Class #3 of Polygon Parent Abstract Class --------------------------


class Hexagon (Polygon):

# overriding abstract method


def noofsides(self):
print("I have 6 sides")

# Child Class #4 of Polygon Parent Abstract Class --------------------------


class Quadrilateral(Polygon):

# overriding abstract method


def noofsides(self):
print("I have 4 sides")

Instantiate objects from the childen classes

In [ ]:
# Create Objects from Children Classes

# Triangle Child Class Object


R = Triangle()
R.noofsides()

# Quadilateral Child Class Object


K = Quadrilateral()
K.noofsides()

# Pentagon Child Class Object


R = Pentagon()
R.noofsides()

# Hexagon Child Class Object


K = Hexagon()
K.noofsides()
Concrete Methods in Abstract Base Classes
concrete classes contain only concrete (normal) methods whereas abstract classes may contains both
concrete methods and abstract methods
concrete classes provide an implementation of abstract methods
the abstract base class can also provide an implementation by invoking the methods via super() in the
child classes

In [ ]:
# Python program invoking a
# method using super()

from abc import ABC, abstractmethod

# create a parent Abstract Class


class Parent(ABC):
# define concrete method in abstract class
def rk(self):
print("Abstract Base Class")

# create a child Concrete Class


class Child(Parent):
# extend
def rk(self):
super().rk()
print("subclass ")

call the child class to instantiate a new object


in the above code, we can invoke the methods in abstract classes by using super()

In [ ]:

# create new object from Concrete Class


new_object = Child()
new_object.rk()

Abstract Properties
abstract classes includes attributes in addition to methods
you can require the attributes in concrete classes by defining them with @abstractproperty

In [1]:
# Python program showing abstract properties

import abc
from abc import ABC, abstractmethod

# create a parent Abstract Class


class parent(ABC):
@abc.abstractproperty # abstract property
def geeks(self):
return "parent class"

# create a child Concrete Class


class child(parent):
@property # reference abstact property
def geeks(self):
return "child class"

try:
new_object = parent()
print(new_object.geeks)
except Exception as err:
print (err)

new_object = child()
print(new_object.geeks)

Can't instantiate abstract class parent with abstract methods geeks


child class

in the above example, the Parent class cannot be instantiated because it has only an abstract version of the
property getter method

Abstract Class Instantiation


abstract classes are incomplete because they have methods which have no body
if python allows creating an object for abstract classes, then using that object, if anyone calls the abstract
method, there is no actual implementation to invoke
so we use an abstract class as a template and according to the need we extend it and build on it before we
can use it.
due to the fact that an abstract class is not a concrete class, it cannot be instantiated
when we create an object from the abstract class, it raises an error

In [ ]:

# Python program showing


# abstract class cannot
# be an instantiation

from abc import ABC,abstractmethod

class Animal(ABC):
@abstractmethod
def move(self):
pass

class Human(Animal):
def move(self):
print("I can walk and run")

class Snake(Animal):
def move(self):
print("I can crawl")

class Dog(Animal):
def move(self):
print("I can bark")

class Lion(Animal):
def move(self):
print("I can roar")

cat = Animal()

Interface
it is like abstract classes but allows child classes to implement multiple classes
cannot define variables (data members) in an interface or constructor functions
only abstract methods
only public functions can be defined, no private and protected functions can be defined
an interface is a set of publicly accessible methods on an object which can be used by other parts of the
program to interact with that object
Interfaces set clear boundaries and help us organize our code better

informal Interfaces - Dynamic Language and Duck Typing


informal Interfaces - Dynamic Language and Duck Typing
There’s no explicit interface keyword in Python like Java/C++ because Python is a dynamically typed
language
in the dynamic language world, things are more implicit
more focus on how an object behaves, rather than it’s type/class
if we have an object that can fly and quack like a duck, we consider it as a duck
this is called “Duck Typing”
to be safe, we often handle the exceptions in a try..except block or use hasattr to check if an object
has the specific method
in the Python world, we often hear “file like object” or “an iterable”
if an object has a read method, it can be treated as a 'file like object'
if it has an __iter__ magic method, it is an iterable
so any object, regardless of it’s class/type, can conform to a certain interface just by implementing the
expected behavior (methods)
these informal interfaces are termed as protocols
since they are informal, they can not be formally enforced
they are mostly illustrated in the documentations or defined by convention

Informal Interface Example

In [ ]:
## Create class called Team
class Team:

# define constructor
def __init__(self, members):
self.__members = members

# define built-in length method


def __len__(self):
return len(self.__members)

# define membership method


def __contains__(self, member):
return member in self.__members

## Instantiate object from Team Class


justice_league_fav = Team(["batman", "wonder woman", "flash"])

## Size protocol
print(len(justice_league_fav))

## Membership protocol
print("batman" in justice_league_fav)
print("superman" in justice_league_fav)
print("cyborg" not in justice_league_fav)

in the above example, by implementing the __len__ and __contains__ method, we can now directly use
the len function on a Team instance and check for membership using the in and not in operators
so we can see that protocols are like informal interfaces

Formal Interfaces - Abstact Base Classes


there are situations where informal interfaces or duck typing in general can cause confusion
for example, a Bird and Aeroplane both can fly()
but they are not the same thing even if they implement the same interfaces / protocols.
Abstract Base Classes or ABCs can help solve this issue
the concept behind ABCs is simple:
we define base classes which are abstract in nature
we define certain methods on the base classes as abstract methods
any objects deriving from these base classes are forced to implement those methods.
any objects deriving from these base classes are forced to implement those methods.
since we’re using base classes, if we see an object has our class as a base class, we can say that this
object implements the interface
that is now we can use types to tell if an object implements a certain interface

Formal Interface - Example


there’s the abc module which has a metaclass named ABCMeta
ABCs (Abstract Base Classes) are created from this metaclass
we can either use it directly as the metaclass of our ABC i.e. something like this
class Bird(metaclass=abc.ABCMeta):
or we can subclass from the abc.ABC class which has the abc.ABCMeta as it’s metaclass already
then we have to use the abc.abstractmethod decorator to mark our methods abstract

In [2]:

import abc

class Bird(abc.ABC):
@abc.abstractmethod
def fly(self):
pass

if any class derives from our base Bird class, it must implement the fly method too

In [ ]:
class Parrot(Bird):
def fly(self):
print("Flying")

p = Parrot()

# check if p is an instance of Bird Class


isinstance(p, Bird)

since our parrot is recognized as an instance of Bird ABC, we can be sure from it’s type that it definitely
implements our desired interface

let’s define another ABC named Aeroplane :

In [ ]:
class Aeroplane(abc.ABC):
@abc.abstractmethod
def fly(self):
pass

class Boeing(Aeroplane):
def fly(self):
print("Flying!")

b = Boeing()

isinstance(p, Aeroplane)
isinstance(b, Bird)

even though both objects have the same method fly


we can differentiate easily which one implements the Bird interface and which implements the
Aeroplane interface.
Interfaces and Multiple Base Classes
multiple parent abstract classes can be implemented in a child class

In [6]:

## define `apple` and `banana` parent classes


class Apple(abc.ABC):
@abc.abstractmethod
def apple_one(self):
pass

class Banana(abc.ABC):
@abc.abstractmethod
def banana_one(self):
pass

## define child class from Apple and Banana


class Fruits(Apple, Banana):

def apple_one(self):
print("Child Class - Apple")

def banana_one(self):
print("Child Class - Banana")

instantiate object and use methods from both parent classes

In [9]:
## instantiate objects

fruit_bowl = Fruits()
fruit_bowl.apple_one() # call function initialized in Apple Base Class
fruit_bowl.banana_one() # call function initialized in Banana Base Class

Child Class - Apple


Child Class - Banana

Reference
Swaroop's Blog
Encapsulation in Python
Abstract Base Classes - Python Docs
Abstract Classes
Informal Interface
Abstract Base Classes for Containers - Python Docs

You might also like