0% found this document useful (0 votes)
9 views15 pages

Class and Objects in Python

Uploaded by

Sreelalitha
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
Download as doc, pdf, or txt
0% found this document useful (0 votes)
9 views15 pages

Class and Objects in Python

Uploaded by

Sreelalitha
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
Download as doc, pdf, or txt
Download as doc, pdf, or txt
You are on page 1/ 15

Class and Objects in Python

Suppose you wish to store the number of books you have, you can simply do that by
using a variable. Or, say you want to calculate the sum of 5 numbers and store it in a
variable, well, that can be done too!
Primitive data structures like numbers, strings, and lists are designed to store simple
values in a variable. Suppose, your name, or square of a number, or count of some
marbles (say).
But what if you need to store the details of all the Employees in your company? For
example, you may try to store every employee in a list, you may later be confused about
which index of the list represents what details of the employee(e.g. which is the name
field, or the empID etc.)
Example:
employee1 = ['John Smith', 104120, "Developer", "Dept. 2A"]
employee2 = ['Mark Reeves', 211240, "Database Designer", "Dept. 11B"]
employee3 = ['Steward Jobs', 131124, "Manager", "Dept. 2A"]
Even if you try to store them in a dictionary, after an extent, the whole codebase will be
too complex to handle. So, in these scenarios, we use Classes in python.
A class is used to create user-defined data structures in Python. Classes define functions,
which are termed methods, that describe the behaviors and actions that an object created
from a class can perform. OOPS concepts in Python majorly deal with classes and
objects.
Classes make the code more manageable by avoiding complex codebases. It does so, by
creating a blueprint or a design of how anything should be defined. It defines what
properties or functions, any object which is derived from the class should have.
IMPORTANT:
A class just defines the structure of how anything should look. It does not point to
anything or anyone in particular. For example, say, HUMAN is a class, which has
suppose -- name, age, gender, city. It does not point to any specific HUMAN out there,
but yes, it explains the properties and functions any HUMAN should or any object of
class HUMAN should have.
An instance of a class is called the object. It is the implementation of the class and exists
in real.
An object is a collection of data (variables) and methods (functions) that access the data.
It is the real implementation of a class.

Consider this example, here Human is a class - It is just a blueprint that defines
how Human should be, and not a real implementation. You may say that "Human" class
just exists logically.
However, "Ron" is an object of the Human class (please refer to the image given above
for understanding). That means, Ron is created by using the blueprint of the Human class,
and it contains the real data. "Ron" exists physically, unlike "Human" (which just exists
logically). He exists in real, and implements all the properties of the class Human, such
as, Ron have a name, he is 15 years old, he is a male, and lives in Delhi. Also, Ron
implements all the methods of Human class, suppose, Ron can walk, speak, eat, and
sleep.
And many humans can be created using the blueprint of class Human. Such as, we may
create 1000s of more humans by referring to the blueprint of the class Human, using
objects.
Quick Tip:
class = blueprint(suppose an architectural drawing). The Object is an actual thing that is
built based on the ‘blueprint’ (suppose a house). An instance is a virtual copy (but not a
real copy) of the object.
When a class is defined, only the blueprint of the object is created, and no memory is
allocated to the class. Memory allocation occurs only when the object or instance is
created. The object or instance contains real data or information.
How to Define a Class in Python?
Classes in Python can be defined by the keyword class, which is followed by the name of
the class and a colon.
Syntax:
class Human:
pass
Indented code below the class definition is considered part of the class body.
'pass' is commonly used as a placeholder, in the place of code whose implementation we
may skip for the time being. "pass" allows us to run the code without throwing an error in
Python.
What is an _init_ Method?
The properties that all Human objects must have been defined in a method called init().
Every time a new Human object is created, __init__() sets the initial state of the object by
assigning the values we provide inside the object’s properties. That
is, __init__() initializes each new instance of the class.
__init__() can take any number of parameters, but the first parameter is always a variable
called self.
The self parameter is a reference to the current instance of the class. It means,
the self parameter points to the address of the current object of a class, allowing us to
access the data of its(the object's) variables.
So, even if we have 1000 instances (objects) of a class, we can always get each of their
individual data due to this self because it will point to the address of that particular object
and return the respective value.
Note:
We can use any name in place of self, but it has to be the first parameter of any function
in the class.
Let us see, how to define __init__() in the Human class:
Code:
class Human:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
In the body of .__init__(), we are using the self variable 3 times, for the following:
self.name = 'name' creates an attribute called name and assigns to it the value of the name
parameter.
self.age = age attribute is created and assigned to the value of age parameter passed.
self.gender = gender attribute is created and assigned to the value of gender parameter
passed.
There are 2 types of attributes in Python:
1. Class Attribute:
These are the variables that are the same for all instances of the class. They do not have
new values for each new instance created. They are defined just below the class
definition.
Code:
class Human:
#class attribute
species = "Homo Sapiens"
Here, the species will have a fixed value for any object we create.
2. Instance Attribute:
Instance attributes are the variables that are defined inside of any function in class.
Instance attributes have different values for every instance of the class. These values
depend upon the value we pass while creating the instance.
Code:
class Human:
#class attribute
species = "Homo Sapiens"
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
Here, name, age, and gender are the instance attributes. They will have different values
for new instances of the class.
For properties that should have a similar value per instance of a class, use class attributes.
For properties that differ per instance, use instance attributes.
Creating an Object in Class
When we create a new object from a class, it is called instantiating an object. An object
can be instantiated by the class name followed by the parentheses. We can assign the
object of a class to any variable.
Syntax:
x = ClassName()
As soon as an object is instantiated, memory is allocated to them. So, if we compare 2
instances of the same class using '==', it will return false(because both will have different
memory assigned).
Suppose, we try to create objects of our Human class, then we also need to pass the
values for name, age, and gender.
Code:
class Human:
#class attribute
species = "Homo Sapiens"
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

x = Human("Ron", 15, "Male")


y = Human("Miley", 22, "Female")
Here, we have created 2 objects of the class Human passing all the required arguments.
Warning: If we do not pass the required arguments, it will throw a TypeError: TypeError:
init() missing 3 required positional arguments: 'name', 'age', and 'gender'.
Let us now see, how to access those values using objects of the class. We can access the
values of the instances by using dot notation.
Code:
class Human:
#class attribute
species = "Homo Sapiens"
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

x = Human("Ron", 15, "Male")


y = Human("Miley", 22, "Female")
print(x.name)
print(y.name)
Output:
Ron
Miley
So, we find that we can access the instance and class attributes just by using the dot
operator.
Code:
class Human:
species = "Homo Sapiens"

def __init__(self, name, age, gender):


self.name = name
self.age = age
self.gender = gender

# x and y are instances of class Human


x = Human("Ron", 15, "male")
y = Human("Miley", 22, "female")

print(x.species) # species are class attributes, hence will have same value for all
instances
print(y.species)

# name, gender and age will have different values per instance, because they are instance
attributes
print(f"Hi! My name is {x.name}. I am a {x.gender}, and I am {x.age} years old")
print(f"Hi! My name is {y.name}. I am a {y.gender}, and I am {y.age} years old")
Output:
Homo Sapiens
Homo Sapiens
Hi! My name is Ron. I am a male, and I am 15 years old
Hi! My name is Miley. I am a female, and I am 22 years old
In the above example, we have our class attributes values same "Homo Sapiens", but the
instance attributes values are different as per the value we passed while creating our
object.
However, we can change the value of class attributes, by
assigning classname.classAttribute with any new value.
Code:
class Human:
#class attribute
species = "Homo Sapiens"
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

Human.species = "Sapiens"
obj = Human("Brek",11,"male")
print(obj.species)
Output:
Sapiens
Instance Methods
An instance method is a function defined within a class that can be called only from
instances of that class. Like init(), an instance method's first parameter is always self.
Let's take an example and implement some functions can class Human can perform --
Code:
class Human:
#class attribute
species = "Homo Sapiens"
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

#Instance Method
def speak(self):
return f"Hello everyone! I am {self.name}"

#Instance Method
def eat(self, favouriteDish):
return f"I love to eat {favouriteDish}!!!"

x = Human("Ciri",18,"female")
print(x.speak())
print(x.eat("momos"))
Output:
Hello everyone! I am Ciri
I love to eat momos!!!
This Human class has two instance methods:
speak(): It returns a string displaying the name of the Human.
eat(): It has one parameter "favouriteDish" and returns a string displaying the favorite
dish of the Human.
Having gained a thorough knowledge of what Python classes, objects, and methods are, it
is time for us to turn our focus toward the OOP core principles, upon which it is built.
Fundamentals of OOPS in Python
There are four fundamental concepts of Object-oriented programming –
Inheritance
Encapsulation
Polymorphism
Data abstraction
Let us now look into each of the OOPS concepts in Python deeply.
Inheritance
People often say to newborn babies that they have got similar facial features to their
parents, or that they have inherited certain features from their parents. It is likely that you
too have noticed that you have inherited some or the other features from your parents.
Inheritance too is very similar to the real-life scenario. But here, the "child classes"
inherit features from their "parent classes." And the features they inherit here are termed
as "properties" and "methods"!
Inheritance is the process by which a class can inherit or derive the properties(or data)
and methods(or functions) of another class. Simply, the process of inheriting the
properties of a parent class into a child class is known as inheritance.
The class whose properties are inherited is the Parent class, and the class that inherits the
properties from the Parent class is the Child class.
Let us see the syntax of inheritance in Python:
Code:
class parent_class:
#body of parent class

class child_class( parent_class): # inherits the parent class


#body of child class
So, we define a normal class as we were defining in our previous examples. Then, we can
define the child class and mention the parent class name, which it is inheriting in
parentheses.
Code:
class Human: #parent class
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender

def description(self):
print(f"Hey! My name is {self.name}, I'm a {self.gender} and I'm {self.age} years
old")

class Boy(Human): #child class


def schoolName(self, schoolname):
print(f"I study in {schoolname}")

b = Boy('John', 15, 'male')


b.description()
b.schoolName("Sunshine Model School")
Output:
Hey! My name is John, I'm a male and I'm 15 years old
I study in Sunshine Model School
In the above example, the child class Boy is inheriting the parent class Human. So, when
we create an object of the Boy class, we can access all the methods and properties of its
parent class, Human, because it is inheriting it.
Also, we have defined a method in the Boy class, which is schoolName . The
method schoolName cannot be accessed by the parent class object. But, we can obviously
call schoolName method by creating the child class object(Boy).
Let's see the issue we face if we are trying to call child class's methods using parent
class's object:
Code:
class Human:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def description(self):
print(f"Hey! My name is {self.name}, I'm a {self.gender} and I'm {self.age} years
old")

class Girl(Human):
def schoolName(self,schoolName):
print("I study in {schoolName}")

h = Human('Lily',20,'girl') # h is the object of the parent class - Human


h.description()
h.schoolName('ABC Academy') #cannot access child class's method using parent class's
object
Output:
Hey! My name is Lily, I'm a girl and I'm 20 years old
Traceback (most recent call last):
File "<string>", line 16, in <module>
AttributeError: 'Human' object has no attribute 'schoolName'
So, here we get the AttributeError: 'Human' object has no attribute 'schoolName'. Because
the child classes can access the data and properties of parent class but vice versa is not
possible.
Super()
The super() function in python is a inheritance-related function that refers to the parent
class. We can use it to find the method with a particular name in an object’s superclass. It
is a very useful function. Let us see how it works --
Syntax: This is the syntax of the super function. We write the super() keyword followed
by the method name we want to refer from our parent class.
super().methodName()
Code:
class Human:
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def description(self):
print(f"Hey! My name is {self.name}, I'm a {self.gender} and I'm {self.age} years
old")

def dance(self):
print("I can dance")

class Girl(Human):
def dance(self):
print("I can do classic dance")
def activity(self):
super().dance()
g = Girl('Lily', 20, 'girl')
g.description()
g.activity()
Output:
Hey! My name is Lily, I'm a girl and I'm 20 years old
I can dance
Here, we have defined the dance() method in Human and Girl classes. But, both methods
have different implementations as you can see. In Human class, the dance method says "I
can dance", whereas in Girl class, the dance method says "I can do classical dance". So,
let us call the parent class's dance method from the child class.
You can see, in line 19, we are calling the dance method using super().dance(). This will
call the dance method from the Human class. So, it prints "I can dance". Although, there
was already an implementation for dance() in Girl(at line 15).
When we call any method using super(), the method in the superclass will be called even
if there is a method with the same name in the subclass.
Polymorphism
Suppose, you are scrolling through your Instagram feeds on your phone. You suddenly
felt like listening to some music as well, so you opened Spotify and started playing your
favorite song. Then, after a while, you got a call, so you paused all the background
activities you were doing, to answer it. It was your friend's call, asking you to text the
phone number of some person. So, you messaged him the number, and resumed your
activities.
Did you notice one thing? You could scroll through feeds, listen to music, attend/make
phone calls, message -- everything just with a single device - your Mobile Phone! Whoa!
So, Polymorphism is something similar to that. 'Poly' means multiple and 'morph' means
forms. So, polymorphism altogether means something that has multiple forms. Or, 'some
thing' that can have multiple behaviours depending upon the situation.
Polymorphism in OOPS refers to the functions having the same names but carrying
different functionalities. Or, having the same function name, but different function
signature(parameters passed to the function).
A child class inherits all properties from its parent class methods. But sometimes, it wants
to add its own implementation to the methods. There are ample of ways we can
use polymorphism in Python.
Example of Inbuilt Polymorphic Functions
len() is an example of inbuilt polymorphic function. Because, we can use it to calclate the
length of vaious types like string, list, tuple or dictionary, it will just compute the result
and return.
Code:
print(len('deepa'))
print(len([1,2,5,9]))
print(len({'1':'apple','2':'cherry','3':'banana'}))
Output:
5
4
3
Here we have passed a string, list and dictionary to the len function and it computed the
result. So, it is an example of an inbuilt Polymorphic function.
We also have polymorphism with the '+' addition operator. We can use it to 'add' integers
or floats or any arithmetic addition operation. In the other hand, with String, it performs
the 'concatenation' operation.
Code:
x=4+5
y = 'python' + ' programming'
z = 2.5 + 3
print(x)
print(y)
print(z)
Output:
9
python programming
5.5
So, we can see that a single operator '+' has been used to carry out different operations for
distinct data types.
Polymorphism with Class Methods
We can perform polymorphism with the class methods. Let's see how:
Code:
class Monkey:
def color(self):
print("The monkey is yellow coloured!")

def eats(self):
print("The monkey eats bananas!")

class Rabbit:
def color(self):
print("The rabbit is white coloured!")

def eats(self):
print("The rabbit eats carrots!")

mon = Monkey()
rab = Rabbit()
for animal in (mon, rab):
animal.color()
animal.eats()
Output:
The monkey is yellow coloured!
The monkey eats bananas!
The rabbit is white coloured!
The rabbit eats carrots!
Here, we can iterate over the objects of Monkey & Rabbit using one variable - animal,
and it can call the instance methods of both of them. So, here one variable animal is used
to represent the behaviour (color() & eats()) of Monkey as well as Rabbit. So, it is
following the rules of Polymorphism!
Polymorphism with Inheritance
We can have polymorphism with inheritance as well. It is possible to modify a method in
a child class that it has inherited from the parent class, adding its own implementation to
the method. This process of re-implementing a method in the child class is known
as Method Overriding in Python. Here is an example that shows polymorphism with an
inheritance:
Code:
class Shape:
def no_of_sides(self):
pass

def two_dimensional(self):
print("I am a 2D object. I am from shape class")

class Square(Shape):

def no_of_sides(self):
print("I have 4 sides. I am from Square class")

class Triangle(Shape):

def no_of_sides(self):
print("I have 3 sides. I am from Triangle class")

# Create an object of Square class


sq = Square()
# Override the no_of_sides of parent class
sq.no_of_sides()

# Create an object of triangle class


tr = Triangle()
# Override the no_of_sides of parent class
tr.no_of_sides()
Output:
I have 4 sides. I am from Square class
I have 3 sides. I am from Triangle class
Here, the Square and Triangle class has overriden the method of the shape class. So, here
the method no_of_sides has different implementations with respect to different shapes.
So, it is in line with Polymorphism.
Encapsulation
You must have seen medicine capsules, where all the medicines remain enclosed inside
the cover of the capsule. Basically, a capsule encapsulates several combinations of
medicine.
Similarly, in programming, the variables and the methods remain enclosed inside a
capsule called the 'class'! Yes, we have learned a lot about classes in Python and we
already know that all the variables and functions we create in OOP remain inside the
class.

The process of binding data and corresponding methods (behavior) together into a single
unit is called encapsulation in Python.
In other words, encapsulation is a programming technique that binds the class members
(variables and methods) together and prevents them from being accessed by other classes.
It is one of the concepts of OOPS in Python.
Encapsulation is a way to ensure security. It hides the data from the access of outsiders.
An organization can protect its object/information against unwanted access by clients or
any unauthorized person by encapsulating it.
Getters and Setters
We mainly use encapsulation for Data Hiding. We do so by
defining getter and setter methods for our classes. If anyone wants some data, they can
only get it by calling the getter method. And, if they want to set some value to the data,
they must use the setter method for that, otherwise, they won't be able to do the same. But
internally, how these getter and setter methods are performed remains hidden from the
outside world.
Code of getter & setter in Encapsulation
class Library:
def __init__(self, id, name):
self.bookId = id
self.bookName = name

def setBookName(self, newBookName): #setters method to set the book name


self.bookName = newBookName

def getBookName(self): #getters method to get the book name


print(f"The name of book is {self.bookName}")

book = Library(101,"The Witchers")


book.getBookName()
book.setBookName("The Witchers Returns")
book.getBookName()
Output:
The name of book is The Witchers
The name of book is The Witchers Returns
In the above example, we defined the getter getBookName() and setter setBookName() to
get and set the names of books respectively. So, now we can only get and set the book
names upon calling the methods, otherwise, we cannot directly get or modify any value.
This promotes high security to our data, because others are not aware at a deep level of
how the following methods are implemented(if their access is restricted).
We can also promote safety of our data using access modifiers. Let's see what are access
modifiers.
Access Modifiers
Access modifiers limit access to the variables and methods of a class. Python provides
three types of access modifiers private, public, and protected.
In Python, we don’t have direct access modifiers like public, private, and protected. We
can achieve this by using single underscore and double underscores.
Public Member: Accessible anywhere from outside the class.
Private Member: Accessible only within the class
Protected Member: Accessible within the class and it's sub-classes
Single underscore _ represents Protected class. Double underscore __ represents Private
class.
Suppose we try to make an Employee class:
Code:
class Employee:
def __init__(self, name, employeeId, salary):
self.name = name #making employee name public
self._empID = employeeId #making employee ID protected
self.__salary = salary #making salary private

def getSalary(self):
print(f"The salary of Employee is {self.__salary}")

employee1 = Employee("John Gates", 110514, "$1500")

print(f"The Employee's name is {employee1.name}")


print(f"The Employee's ID is {employee1._empID}")
print(f"The Employee's salary is {employee1.salary}") #will throw an error because
salary is defined as private
Here, we have made the employee's name public, employee's ID protected, and the
employee's salary private. Suppose we try to print all the values. Now, we will be able to
access the employee's name or his ID, but not the salary(because it is private). Look into
the error below:
Output:
The Employee's name is John Gates
The Employee's ID is 110514
Traceback (most recent call last):
File "<string>", line 14, in <module>
AttributeError: 'Employee' object has no attribute 'salary'
However, we can access the employee's salary by calling that getter
method getSalary() we have created in our Employee class.
Now, you might have understood the importance of getters and setters, and also the
access modifiers which restricts the access to your data.
Complete code:
class Employee:
def __init__(self, name, employeeId, salary):
self.name = name #making employee name public
self._empID = employeeId #making employee ID protected
self.__salary = salary #making salary private

def getSalary(self):
print(f"The salary of Employee is {self.__salary}")
employee1 = Employee("John Gates", 110514, "$1500")

print(f"The Employee's name is {employee1.name}")


print(f"The Employee's ID is {employee1._empID}")
employee1.getSalary() #will be able to access the employee's salary now using the getter
method
Output:
The Employee's name is John Gates
The Employee's ID is 110514
The salary of Employee is $1500
We can access private members from outside of a class by creating public method to
access private members (just like we did above). There is one more method to get access
called name mangling.
A protected data member is used when inheritance is used and you want the data
members to have access only to the child classes.
So, encapsulation protects an object from unauthorized access. It allows private and
protected access levels to prevent accidental data modification.
Abstraction
It is likely that you are reading this article on your laptop, phone, or tablet. You are also
probably making notes, and highlighting important points, and you may be saving some
points in your internal files while reading it. As you read this, all you see before you is a
'screen' and all this data that is shown to you. As you type, all you see are the keys on the
keyboard and you don't have to worry about the internal details, like how pressing a key
may lead to displaying that word onscreen. Or, how clicking on a button on your screen
could open a new tab!
So, everything we can see here is at an abstract level. We are not able to see the internal
details, but just the result it is producing(which actually matters to us).
Abstraction in a similar way just shows us the functionalities anything holds, hiding all
the implementations or inner details.
The main goal of Abstraction is to hide background details or any unnecessary
implementation about the data so that users only see the required information. It helps in
handling the complexity of the codes.
Key Points of Abstract Classes
Abstraction is used for hiding the background details or any unnecessary implementation
of the data, so that users only see the required information.
In Python, abstraction can be achieved by using abstract classes
A class that consists of one or more abstract methods is called the "abstract class".
Abstract methods do not contain any implementation of their own.
Abstract class can be inherited by any subclass. The subclasses that inherit the abstract
classes provide the implementations for their abstract methods.
Abstract classes can act like blueprint to other classes, which are useful when we are
designing large functions. And the subclass which inherits them can refer to the abstract
methods for implementing the features.
Python provides the abc module to use the abstraction
Syntax of Abstract Class in Python
To use abstraction, it is mandatory for us to import ABC class from the abc module.
Syntax:
from abc import ABC
class ClassName(ABC):
ABC stands for Abstract Base class. The abc module provides the base for defining
Abstract Base classes (ABC).
Let us take an example and see the implementation of abstract class:
So, the above code for your reference is:
Code:
from abc import ABC

class Vehicle(ABC): # inherits abstract class


#abstract method
def no_of_wheels(self):
pass

class Bike(Vehicle):
def no_of_wheels(self): # provide definition for abstract method
print("Bike have 2 wheels")

class Tempo(Vehicle):
def no_of_wheels(self): # provide definition for abstract method
print("Tempo have 3 wheels")

class Truck(Vehicle): # provide definition for abstract method


def no_of_wheels(self):
print("Truck have 4 wheels")

bike = Bike()
bike.no_of_wheels()
tempo = Tempo()
tempo.no_of_wheels()
truck = Truck()
truck.no_of_wheels()
Output:
Bike have 2 wheels
Tempo have 3 wheels
Truck have 4 wheels
Here, we have an abstract class Vehicle. It is abstract because it is inheriting the abstract
class abc. The class Vehicle have an abstract method called no_of_wheels, which do not
have any definition, because abstract methods are not defined(or abstract methods remain
empty, and they expects the classes inheriting the abstract classes to provide the
implementation for the method ).
But, other classes which inherits the Vehicle class, like Bike, Tempo or Truck, defines
the method no_of_wheels, and they provide their own implementation for the abstract
method. Suppose, bike have 2 wheels, so it prints "Bike have 2 wheels" in the inherited
abstract method no_of_wheels. And, similarly, Tempo and Truck classes also provide
their own implementations.
Some notable points on Abstract classes are:
Abstract classes cannot be instantiated. In simple words, we cannot create objects for the
abstract classes.
An Abstract class can contain the both types of methods -- normal and abstract method.
In the abstract methods, we do not provide any definition or code. But in the normal
methods, we provide the implementation of the code needed for the method.
Advantages of OOPS in Python
There are numerous advantages of OOPS concepts in Python, making it favorable for
writing serious softwares. Let us look into a few of them --
Effective problem solving because, for each mini-problem, we write a class that does
what is required. And then we can reuse those classes, which makes it even quicker to
solve the next problem.
Flexibility of having multiple forms of a single class, through polymorphism
Reduced high complexity of code, through abstraction.
High security and data privacy through encapsulation.
Reuse of code, by the child class inheriting properties of parent class through inheritance.
Modularity of code allows us to do easy debugging, instead of looking into hundreds of
lines of code to find a single issue.

You might also like