Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
2 views

OOPs in Python

This document provides an overview of Object-Oriented Programming (OOP) concepts in Python, including classes, objects, constructors, destructors, and various methods. It explains the principles of encapsulation, inheritance, and data abstraction, along with practical examples of how to implement these concepts in Python code. Additionally, it covers built-in class attributes and the garbage collection process in Python.

Uploaded by

ishanvisri16
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

OOPs in Python

This document provides an overview of Object-Oriented Programming (OOP) concepts in Python, including classes, objects, constructors, destructors, and various methods. It explains the principles of encapsulation, inheritance, and data abstraction, along with practical examples of how to implement these concepts in Python code. Additionally, it covers built-in class attributes and the garbage collection process in Python.

Uploaded by

ishanvisri16
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 88

Session-20

OOPs in Python

OOPs concepts with Applications

Trainer: Ms. Nidhi Grover Raheja

1
Session Overview

OOPS in Python

Classes and Objects

Constructors and Destructors

OOPs concept in details

Exercise

2
OOPS in Python

❖ Python is an object-oriented programming language.

❖ It allows us to develop applications using an Object Oriented approach using classes and objects.

❖ Some OOPs concepts:

❑ Class and Object

❑ Data Abstraction

❑ Encapsulation

❑ Polymorphism

❑ Inheritance

❑ Data Hiding

3
class Person: # Create objects for class Person
print(".................... Creating first object .......................")
# Attributes or variables p1 = Person() # p1 is the object of class Person. It is created by self
# Class attributes or class variables calling __init__() constructor
name = "Guest" # class attributes are shared by all objects p1.outputdetails()
age = 0 print("....................Input details for object 1 .....................")
salary = 0 p1.inputdetails("Aditi", 18)
p1.outputdetails()
# Create methods in this class
# constructor --> helps to instantiate an object. It is not compulsory. print(".................... Creating second object .......................")
def __init__(self): # self refers to the current or present object p2 = Person() # 2nd object. It is created by self calling __init__()
print("Instantiating the object............") constructor
self.salary = 1000 p2.outputdetails()
self.age = 18 print("..............Enter values for second object.......................")
p2.inputdetails()
# Other normal methods p2.outputdetails()
def inputdetails(self, n, a, s=5000): print(".................... Creating third object .......................")
self.name = n p3 = Person() # 3rd object. It is created by self calling __init__()
self.salary = s constructor
self.age = a p3.outputdetails()

def outputdetails(self):
print("The name is: ", self.name)
print("The age is: ", self.age)
print("The salary is: ", self.salary)
Class and Objects
What is a class and it’s object?

❖A Class is a user-defined prototype for an object that defines a set of attributes that
characterize any object of the class. It encapsulates or binds together the data members
(class variables and instance variables) and methods that use these data members
together in one unit.
❖A class contains data members and methods that use that data members.
❖An Object is the instance of a class and the process of creation of an object i.e. instance
of a class is called Instantiation. Example: An object obj1 that belongs to a class say,
Rectangle, for example, is an instance of the class Rectangle.
❖The method __init__() is a special method, which is called class constructor or
initialization method that Python calls when you create a new instance of this class.
❖You can use classes to model real-world objects, such as people, animals, vehicles,
books, and buildings. You can also use classes to model virtual objects, such as web
servers, directory trees, chatbots, and file managers
13
Defining classes in Python
How to create a class?

❖ The class statement creates a new class definition. The name of the class immediately follows the
keyword class followed by a colon as follows −

❖ Syntax of class :

class ClassName:
'Optional class documentation string’
class_suite

Where:

❑ The class has a documentation string, which can be accessed via ClassName.__doc__.

❑ The class_suite consists of all the component statements defining class members, data attributes
and functions.

14
Members of a Class
Who are the members of a class?

Members of a Python class are the attributes and methods that define the behavior and
properties of the objects created from the class:

1. Attributes or Variables: Variables defined inside class that store data for the class to work.
Types of attributes in a class:
a. Class attribute (Class variable)
b. Data or Instance Attribute (Instance variable)

2. Methods: Methods are the functions define the behavior of the class and its objects. They
are functions defined within the class and operate on class or instance data. A function that
is defined in a class definition and is using data members of the class for performing a
specified task. A method is called with an object of class using dot operator.
Types of methods in a class:
a. Instance methods
b. Class methods
c. Static methods
d. Magic (Dunder) Methods 15
Attributes - Class Attributes
Key features of Class attributes

16
Attributes - Data or Instance Attributes
Key features of Data or Instance attributes

17
class Vehicle: # Accessing instance attributes
wheels = 4 # Class attribute print(car.color) # Output: Red
def __init__(self, color): print(bike.color) # Output: Blue
self.color = color # Instance (data) attribute
# Changing the instance attribute
# Accessing class attribute car.color = "Green"
print(Vehicle.wheels) # Output: 4 print(car.color) # Output: Green
print(bike.color) # Output: Blue
# Creating instances with different data attributes
car = Vehicle("Red")
bike = Vehicle("Blue")

# Accessing class attributes


print(car.wheels) # Output: 4
print(bike.wheels) # Output: 4

# Changing the class attribute


Vehicle.wheels = 2
print(car.wheels) # Output: 2
print(bike.wheels) # Output: 2
Class Attributes versus Data Attributes

Feature Class Attributes Data Attributes (Instance Attributes)

Belongs To Class Individual instances


Scope Shared among all instances Specific to a particular instance
Declared using self in instance
Declaration Declared directly in the class
methods
Affects all instances unless
Modification Effect Affects only the specific instance
overridden
Accessible only via the specific
Accessibility Accessible via class or instance
instance
Methods – Instance Methods
Methods- Class Method
Methods- Static Method
Methods- Magic Methods
import math
# Create two vectors
class Vector:
v1 = Vector(1, 2)
def __init__(self, x, y):
v2 = Vector(3, 4)
self.x = x
self.y = y
# Add the vectors
v3 = v1 + v2
def __add__(self, other): # Overload `+` operator
return Vector(self.x + other.x, self.y + other.y)
# Print the vectors and their lengths
print("v1:", v1) # Output: v1: Vector(1, 2)
def __str__(self):
print("Length of v1:", len(v1)) # Output: Length of v1: 2
return f"Vector({self.x}, {self.y})"
print("v2:", v2) # Output: v2: Vector(3, 4)
def __len__(self):
print("Length of v2:", len(v2)) # Output: Length of v2: 5
"""Return the magnitude (length) of the vector."""
return round(math.sqrt(self.x ** 2 + self.y ** 2))
print("v3 (v1 + v2):", v3) # Output: v3 (v1 + v2): Vector(4, 6)
print("Length of v3:", len(v3)) # Output: Length of v3: 7
Output:
Comparison of Types of Methods in a Class
Method Type Decorator Takes self? Takes cls? Use Case

Operates on instance-specific
Instance Method None Yes No
attributes.

Operates on class-level
Class Method @classmethod No Yes
attributes or methods.

Utility methods related to the


Static Method @staticmethod No No class but independent of
instance or class.

Customize or overload default


__init__, __add__,
Magic Method Depends Depends behaviors (e.g., initialization,
etc.
operators).
Session-22

Constructors & Destructors in Python

Constructors & Destructors

Trainer: Ms. Nidhi Grover Raheja

29
Session Overview

OOPS in Python

Classes and Objects

Constructors and Destructors

OOPs concept in details

Exercise

30
Object Instantiation using Constructors
What is a constructor?

❖A constructor is a special type of method which is used to initialize the

instance members of the class.

❖Constructors can be of two types.

❑Parameterized Constructor

❑Non-parameterized Constructor

❖Constructor definition is executed when we create the object of this class.

31
Creating the constructor
How to create a constructor?

❖ In python, the method __init__() calls the constructor of the class. This method is called when the class is instantiated to

initialize the class attributes. Syntax:

• def __init__(self, arguments)

❖ "__init__" is a reserved method in python classes. It is known as a constructor in object oriented concepts. This method

called when an object is created from the class and it allow the class to initialize the attributes of a class.

❖ Here self represents the instance of the class. By using the "self" keyword we can access the attributes and methods of the

class in python.

❖ Any number of arguments can be passed depending upon __init__() definition.

❖ To create object instances of a class, we call the class using class name and pass in whatever arguments its __init__() method accepts.

32
Class & Object Example
Class & Object Demonstration

class Student:
'Common base class for all Students’ # A documentation string, which can be accessed via ClassName.__doc__
stuCount = 0 # class variable declared

def __init__(self, name, age):


self.name = name
self.age = age
Student.stuCount += 1

def displayCount(self):
print ("Total Students are %d" % Student.stuCount)

def displayStudent(self):
print ("Name : ", self.name, ", Age: ", self.age)

stu1 = Student(“Priya", 18) #This would create first object of Student class"
stu2 = Student(“Smriti", 20) #This would create second object of Student class"
stu1.displayStudent() # Calling method with object stu1
stu2.displayStudent () # Calling method with object stu2
print ("Total Students are %d" % Student.stuCount) # Accessing class variable stuCount shared by all objects

33
Built-In Class Attributes
Built-In Class Attributes

❖ Every Python class keeps following built-in attributes and they can be accessed using dot operator like any
other attribute −

❑ __dict__ − Dictionary containing the class's namespace.

❑ __doc__ − Class documentation string or none, if undefined.

❑ __name__ − Class name.

❑ __module__ − Module name in which the class is defined. This attribute is "__main__" in
interactive mode.

❑ __bases__ − A possibly empty tuple containing the base classes, in the order of their occurrence in
the base class list.

34
Garbage Collection in Python
Freeing up the memory

❖Python deletes unneeded objects (built-in types or class instances) automatically to free the
memory space.

❖The process by which Python periodically reclaims blocks of memory that no longer are in use
is termed as Garbage Collection.

❖Python's garbage collector runs during program execution and is triggered when an object's
reference count reaches zero i.e. no reference to an object exists.

❖ User usually does not notice when the garbage collector destroys an object and reclaims its
space.

❖However, a class can implement the special method __del__(), called a destructor, that is
invoked when the instance is about to be destroyed. This method might be used to clean up
any non-memory resources used by an instance.

35
Use Destructors
How to use Destructors?

class Person:
def __init__(self, name):
self.name = name
print(f"Person {self.name} created.")

def __del__(self):
print(f"Person {self.name} deleted.")

# Create objects
p1 = Person("Alice")
p2 = Person("Bob")

# Explicitly delete objects


del p1
del p2

print("End of program.") 36
Data Abstraction, Access
Modifiers, Encapsulation and
Inheritance
Data Abstraction

❖Data Abstraction is the concept of hiding the internal details and

describing things in simple terms.

❖For example, a method that adds two integers. The internal processing

of the method is hidden from the outer world.

❖ There are many ways to achieve abstraction in object-oriented

programming, such as ENCAPSULATION and INHERITANCE.


38
class Employee:
def __init__(self, name, salary, department):
# Public data member
self.name = name # Can be accessed anywhere

# Protected data member


self._salary = salary # Can be accessed in the class and subclasses

# Private data member


self.__department = department # Accessible only within the class

# Public method to get the private member


def get_department(self):
return self.__department

# Public method to set the private member


def set_department(self, department):
self.__department = department
# Create an instance of Employee
emp = Employee("Alice", 50000, "HR")

# Accessing the public data member


print(f"Public Member Employee Name: {emp.name}") # Output: Employee Name: Alice

# Accessing the protected data member (possible but discouraged)


print(f"Protected Member Employee Salary: {emp._salary}") # Output: Employee Salary: 50000

# Accessing the private data member (direct access not allowed)


# print(emp.__department) # Raises an AttributeError
print(f"Private Member Department: {emp._Employee__department}") # Possible Indirectly by Name Mangling

# Accessing the private data member using public methods


print(f"Employee Department: {emp.get_department()}") # Output: Employee Department: HR

# Modifying the private data member using the setter


emp.set_department("Finance")
print(f"Updated Department: {emp.get_department()}") # Output: Updated Department: Finance
Output:
Feature Public Protected Private
Double underscore prefix
Syntax No prefix (name) Single underscore prefix (_name)
(__name)
Accessible within the class and Accessible only within the class
Accessible everywhere (inside
Access Level subclasses (discouraged outside (name mangling restricts direct
and outside the class).
the class but possible). access).
For data that should be
For data that should be freely For data that should be accessed
Use Case completely encapsulated within
accessible. by the class and subclasses.
the class.
No restrictions; least
Encapsulation Moderate encapsulation. Highest level of encapsulation.
encapsulation.
Inherited but renamed due to
Inherited by subclasses and Inherited by subclasses and
Inheritance Behavior name mangling
freely accessible. accessible.
(_ClassName__name).

Can be accessed and modified Can be accessed and modified Cannot be accessed directly;
Access Outside Class
directly. (not recommended). requires getter/setter methods.

Example self.name self._salary self.__department

Indirect via name mangling


Accessibility by Naming Direct (object.name) Direct (object._name) (object._ClassName__name) or
methods.
Encapsulation

❖Encapsulation is a fundamental concept of object-oriented


programming (OOP) that involves bundling data (attributes) and
methods (functions) that work on the data within a single unit called a
class.
❖It restricts direct access to some class members and methods of an
object to protect the internal state and ensure controlled interaction.
❖Encapsulation is the technique used to implement abstraction in object-
oriented programming.

45
class BankAccount: # Usage
def __init__(self, account_holder, balance): account = BankAccount("Alice", 1000)
self.account_holder = account_holder # Public attribute
self.__balance = balance # Private attribute
# Access public attribute
# Getter method for private attribute print(account.account_holder) # Output: Alice
def get_balance(self):
return self.__balance # Access private attribute (not allowed)
# print(account.__balance) # Raises AttributeError
# Setter method with validation
def deposit(self, amount): # Access private data using methods
if amount > 0: print(account.get_balance()) # Output: 1000
self.__balance += amount
else: # Deposit and withdraw money
print("Deposit amount must be positive.") account.deposit(500)
print(account.get_balance()) # Output: 1500
# Method to withdraw money with validation
def withdraw(self, amount): account.withdraw(2000) # Output: Insufficient funds.
if amount > self.__balance: print(account.get_balance()) # Output: 1500
print("Insufficient funds.")
elif amount > 0:
self.__balance -= amount
else:
print("Withdrawal amount must be positive.")
Output:
Polymorphism

❖Polymorphism contains two words "poly" and "morphs". Poly means ‘many’ and

Morphs means ‘form’.

❖Polymorphism means that one task can be performed in multiple ways.

❖Implemented in two ways:

❑Overloading Methods

❑Overloading Operators

52
Method Overloading
Polymorphism through method calling

❖Overloading, in the context of programming, refers to the ability of a function or an operator to behave in
different ways depending on the parameters that are passed to the function, or the operands that the operator a
cts on.

❖Several ways to call a method is called polymorphism through method overloading. In Python you can define a
method in such a way that there are multiple ways to call a method.

❖Given a single method or function, we can specify the number of parameters during method calling.

❖Depending on the function definition, it can be called with zero, one, two or more parameters. This is known a
s method overloading.

❖Overloading a method fosters reusability. For instance, instead of writing multiple methods that differ only
slightly, we can write one method and overload it.

❖Overloading also improves code clarity and eliminates complexity.

56
Method Overloading (contd.)
Polymorphism through method calling

To overload a user-defined function in Python, we need to write the function logic in such a way that depending
upon the parameters passed, a different piece of code executes inside the function. Take a look at the following
example:

class Employee:
def greeting(self, name=None):
if name is not None:
print('Hello Employee: ' + name)
else:
print('Hello Guest')

# Creating a class instance


emp = Employee()

# Call the method


emp.greeting()

# Call the method and pass a parameter


emp.greeting('Raman') 57
Operator Overloading
Polymorphism through operator overloading

❖When we use an operator on user defined data types then automatically a special function or
magic function associated with that operator is invoked. Changing the behavior of operator is as
simple as changing the behavior of method or function.

❖To perform operator overloading, Python provides some special function or Magic Function
that is automatically invoked when it is associated with that particular operator. For
example, when we use + operator, the magic method __add__ is automatically invoked in
which the operation for + operator is defined.

❖By changing this magic method’s code, we can give extra meaning to the + operator.

❖Suppose you have created a class to represent vectors. Suppose we want to use the simple
mathematical addition (+) operator to add them. Python does not allow this!!.

❖For this we must define an __add__ method in our class to perform vector addition and then the
addition operator (+) will add the two vectors in the same way as it adds two numbers: 58
Magic Method for operator overloading Operator/Action Example

__add__(self, other) + (Addition) obj1 + obj2

__sub__(self, other) - (Subtraction) obj1 - obj2

__mul__(self, other) * (Multiplication) obj1 * obj2

__mod__(self, other) % (Modulus) obj1 % obj2

__pow__(self, other) ** (Exponentiation) obj1 ** obj2

__eq__(self, other) == (Equality) obj1 == obj2

__ne__(self, other) != (Inequality) obj1 != obj2

__lt__(self, other) < (Less than) obj1 < obj2

__le__(self, other) <= (Less than or equal to) obj1 <= obj2

__gt__(self, other) > (Greater than) obj1 > obj2

__ge__(self, other) >= (Greater than or equal to) obj1 >= obj2
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y

def __add__(self, other):


return Vector(self.x + other.x, self.y + other.y)

def __sub__(self, other):


return Vector(self.x - other.x, self.y - other.y)

def __repr__(self):
return f"Vector({self.x}, {self.y})"

# Creating objects
v1 = Vector(2, 3)
v2 = Vector(4, 1)

# Adding two vectors using overloaded `+` operator


v3 = v1 + v2
print(v3) # Output: Vector(6, 4)

# Subtracting two vectors using overloaded `-` operator


v4 = v1 - v2
print(v4) # Output: Vector(-2, 2)
Inheritance
Reusability using Inheritance

❖ Inheritance is the object-oriented programming concept where an object is based on another object.

❖ Inheritance is the mechanism of code reuse.

❖ The object that is getting inherited is called superclass and the object that inherits the superclass is called

subclass.

❖ Instead of starting from a scratch, you can create a class by deriving it from a pre-existing class by listing

the parent class in parentheses after the new class name.

❖ The child class inherits the attributes of its parent class, and you can use those attributes as if they were

defined in the child class. A child class can also override data members and methods from the parent.
64
Inheritance (contd.)
Syntax & Practical Demo

❖ Syntax:

❖ Derived classes are declared much like their parent class; however, a list of base classes to
inherit from is given after the class name −

class SubClassName (ParentClass1[, ParentClass2, ...]):


'Optional class documentation string'
class_suite

65
Inheritance (contd.)
Syntax & Practical Demo

# Parent Class # Creating an object of the Parent Class


class Vehicle: vehicle = Vehicle("Generic", "Model X")
def __init__(self, brand, model): print(vehicle.details())
self.brand = brand
self.model = model # Creating an object of the Child Class
car = Car("Toyota", "Camry", 4)
def details(self): print(car.details())
return f"Vehicle: {self.brand} {self.model}"

# Child Class
class Car(Vehicle):
def __init__(self, brand, model, doors):
super().__init__(brand, model) # Call the parent class's constructor
self.doors = doors

def details(self):
return f"Car: {self.brand} {self.model}, Doors: {self.doors}"
66
Types of Inheritance
Single Inheritance

68
class ParentClass:
def __init__(self):
self.value = 10

def display(self):
print("ParentClass display:", self.value)

class ChildClass(ParentClass):
def __init__(self):
super().__init__()
self.child_value = 20

def display_child(self):
print("ChildClass display:", self.child_value)

# Creating an instance of ChildClass


child = ChildClass()
child.display() # Inherited from ParentClass
child.display_child() # Defined in ChildClass
Types of Inheritance
Multiple Inheritance

70
class ParentClass1: # Creating an instance of ChildClass
def __init__(self): child = ChildClass()
self.value1 = 10 child.display1() # Inherited from ParentClass1
child.display2() # Inherited from ParentClass2
def display1(self): child.display_child() # Defined in ChildClass
print("ParentClass1 display:", self.value1)

class ParentClass2:
def __init__(self):
self.value2 = 20

def display2(self):
print("ParentClass2 display:", self.value2)

class ChildClass(ParentClass1, ParentClass2):


def __init__(self):
ParentClass1.__init__(self)
ParentClass2.__init__(self)

def display_child(self):
print("ChildClass display: Combined values:", self.value1, self.value2)
Types of Inheritance
Multi-Level Inheritance

72
class ParentClass: # Creating an instance of GrandChildClass
def __init__(self): grandchild = GrandChildClass()
self.value = 10 grandchild.display() # Inherited from ParentClass
grandchild.display_child() # Inherited from ChildClass
def display(self): grandchild.display_grandchild() # Defined in GrandChildClass
print("ParentClass display:", self.value)

class ChildClass(ParentClass):
def __init__(self):
super().__init__()
self.child_value = 20

def display_child(self):
print("ChildClass display:", self.child_value)

class GrandChildClass(ChildClass):
def __init__(self):
super().__init__()
self.grandchild_value = 30

def display_grandchild(self):
print("GrandChildClass display:", self.grandchild_value)
Types of Inheritance
Hierarchical Inheritance

74
class ParentClass:
def __init__(self):
self.value = 10

def display(self):
print("ParentClass display:", self.value)

class ChildClass1(ParentClass):
def display_child1(self):
print("ChildClass1 display")

class ChildClass2(ParentClass):
def display_child2(self):
print("ChildClass2 display")

# Creating instances of ChildClass1 and ChildClass2


child1 = ChildClass1()
child2 = ChildClass2()

child1.display() # Inherited from ParentClass


child1.display_child1() # Defined in ChildClass1

child2.display() # Inherited from ParentClass


child2.display_child2() # Defined in ChildClass2
Types of Inheritance
Hybrid Inheritance

Generally A Combination of multiple + multilevel inheritance

76
class ParentClass1: class GrandChildClass(ParentClass2, ChildClass):
def __init__(self): def __init__(self):
self.value1 = 10 ParentClass2.__init__(self)
ChildClass.__init__(self)
def display1(self):
print("ParentClass1 display:", self.value1) def display_grandchild(self):
print("GrandChildClass display:", self.value2,
class ParentClass2: self.child_value)
def __init__(self):
self.value2 = 20 # Creating an instance of GrandChildClass
grandchild = GrandChildClass()
def display2(self): grandchild.display1() # Inherited from ParentClass1
print("ParentClass2 display:", self.value2) grandchild.display2() # Inherited from ParentClass2
grandchild.display_child() # Inherited from ChildClass
class ChildClass(ParentClass1): grandchild.display_grandchild() # Defined in GrandChildClass
def __init__(self):
super().__init__()
self.child_value = 30

def display_child(self):
print("ChildClass display:", self.child_value)
Inheritance Type Description Example

One child class inherits from one


Single Inheritance ParentClass → ChildClass
parent class.
One child class inherits from ParentClass1, ParentClass2 →
Multiple Inheritance
multiple parent classes. ChildClass
A child class inherits from a parent
class, and another class inherits ParentClass → ChildClass →
Multilevel Inheritance
from the child class, forming a GrandChildClass
chain of inheritance.
Multiple child classes inherit from ParentClass → ChildClass1,
Hierarchical Inheritance
a single parent class. ChildClass2
A combination of more than one
type of inheritance, where a class ParentClass1, ParentClass2 →
Hybrid Inheritance
inherits from more than one class ChildClass → GrandChildClass
in a hybrid form.
Method Resolution Order (MRO)
Resolve Method calls and decide order of Parent Classes

➢ MRO is a concept used in inheritance. It is the order in which a method is searched for in a
classes hierarchy and is especially useful in Python because Python supports multiple
inheritance.

➢ In Python, the MRO is from bottom to top and left to right. This means that, first, the method
is searched in the class of the object. If it’s not found, it is searched in the immediate super
class.

➢ In the case of multiple super classes, it is searched left to right, in the order by which was
declared by the developer. For

➢ Example:
def class C(B, A)

➢ In this case, the MRO would be C -> B -> A. Since B was mentioned first in the class
declaration, it will be searched for first while resolving a method. 79
Method Resolution Order (MRO)
Resolve Method calls and decide order of Parent Classes

➢ Example:
def class C(B, A)

➢ In this case, the MRO would be C -> B -> A. Since B was mentioned first in the class
declaration, it will be searched for first while resolving a method.

➢ To view the MRO of a class:

➢ Use the mro() method, it returns a list

Eg: C.mro()

➢ Use the _mro_ attribute, it returns a tuple

Eg: C.__mro__
80
class A: # Creating an instance of D
pass obj = D()

class B(A): # Printing the MRO


pass print(D.mro()) # prints a list of class hierarchy
print(D.__mro__) # # prints a tuple of class hierarchy
class C(A):
pass

class D(B, C):


pass
class A: class D(B, C):
def show(self): pass # No show() method here, so it will follow MRO
print("Method in A")
# Creating an instance of D
class B(A): obj = D()
def show(self): obj.show()
print("Method in B")
# Printing the MRO
class C(A): print(D.mro()) # prints a list of class hierarchy
def show(self): print(D.__mro__) # # prints a tuple of class hierarchy
print("Method in C")
In the case where it is not present in B, then the method from
its immediate super class (A) would be called. So, the MRO for
this case is: B -> A
The MRO for this case is:
C -> B -> A
The method only existed in A, where it was searched for last.
The MRO for this can be a bit tricky. The immediate superclass for D is C, so if the method is not found in D, it is searched
for in C. However, if it is not found in C, then you have to decide if you should check A (declared first in the list of C’s
super classes) or check B (declared in D’s list of super classes after C).
In Python 3 onwards, this is resolved as first checking A. So, the MRO becomes:
D -> C -> A -> B
Super Keyword
Call Parents from Child

• The super() keyword in Python is used to call a method or constructor of a parent


class.
• It is especially useful in inheritance when you want to reuse the parent class's
functionality in a child class while extending or customizing it.

The super() function automatically resolves the MRO and ensures that the correct parent method is called.
This is particularly useful in complex hierarchies with multiple inheritance. 86
Example 1: Calling Parent Constructor
Example 1: Calling Parent Constructor

class Parent:
def __init__(self, name):
print("In Parent Constructor!!")
self.name = name

class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # Call Parent class's constructor
print("In Child Constructor!!")
self.age = age

def display(self):
print(f"Name: {self.name}, Age: {self.age}")

# Creating an object of the Child class


child = Child("Alice", 10)
child.display()
87
Example 2: Calling Parent Methods
Example 2: Calling Parent Methods

class Parent:
def greet(self):
print("Hello from Parent!")

class Child(Parent):
def greet(self):
super().greet() # Call Parent class's greet method
print("Hello from Child!")

# Creating an object of the Child class


child = Child()
child.greet()

88

You might also like