Introduction
Object-Oriented programming (OOP) is the most popular programming paradigm based on the concept of Classes and Objects, which contains data members (fields) and member functions (methods). It can translate every real-time living and non-living object into programming.
In OOP, objects are instances of classes, which define the attributes and methods that the objects will have. Classes can inherit attributes and methods from other classes, which can help to reduce code duplication and make it easier to maintain and extend code.
Some key concepts of OOP include:
- Encapsulation: The practice of hiding the implementation details of an objectās behavior and providing a public interface for interacting with the object.
- Abstraction: The process of simplifying complex systems by breaking them down into smaller, more manageable parts, and modeling those parts as objects.
- Inheritance: The ability of a class to inherit attributes and methods from another class, which can help to reduce code duplication and make it easier to create specialized classes.
- Polymorphism: The ability of different objects to respond to the same
message in different ways, based on their specific implementations of
the messageās corresponding method.
![]() |
Key Concepts of Object-Oriented Programming |
In this tutorial, we will try to learn about Object-Oriented Programming from the very basics and will implement all the concepts through Python Programming.
Why Object-Oriented Programming?
We got a brief idea of OOP but thatās not enough to understand the whole concept. We will dig it more here. Letās start with the concept of the object through real-life examples.
In simple words, youāre an object, Iām an object, every person is an object and every individual object has some attributes and behavior. For example, if we consider people as objects then they have some attributes like Name, Surname, Age, Gender, etc. at the same time they carry some behavior like playing, drawing, singing, dancing, and many more.
Iām assuming you are familiar with Procedural Programming (where a program is written as a series of steps or procedures. Each procedure performs a specific task and the program is organized into modules, or sub-programs or functions, that call the procedures, and it is a top-to-down approach).
Consider a real-life example of an employee data set where every employee has Emp. ID, Name, Surname, Age, Contact, and address. These are nothing but attributes and the values can be easily stored using variables in a program. We can write functions to do some kind of data manipulation with those values.
Itās a traditional way to do so. But think about what happens if all the same variables and functions will use for 100 employees. In simple words, Itās not gonna work as we think because every employee has his/her own identity and it is defined by attributes and behavior.
It means every employee must have his/her own variables and functions and they should not be shared with other employees. In this scenario, Object-Oriented Programming is the solution.
I hope now you got an idea of OOP and why itās so important in Programming.
What is Class in Object-Oriented Programming?
In object-oriented programming (OOP), a class is a blueprint or template that defines the attributes (data) and methods (functions) that objects of that class can have. A class is a user-defined data type that is used to create objects, which are instances of that class.
A class defines the structure and behavior of objects, and it encapsulates related data and behavior into a single unit. The attributes of a class are typically represented by member variables or instance variables, while the methods of a class are represented by member functions.
For example, consider a class named āPersonā that defines the attributes and methods of a person. The āPersonā class may have attributes such as name, age, gender, and address, and methods such as walking, talking and eating. Objects of the āPersonā class can be created by instantiating the class, which creates a new instance of the class with its own set of attributes and methods.
Classes can also inherit attributes and methods from other classes, which is known as inheritance. Inheritance allows for the creation of specialized classes that extend or modify the behavior of a base class, without having to rewrite the code for the base class.
Overall, classes are an essential feature of OOP and provide a way to organize code into reusable and modular units, which can simplify the development and maintenance of complex software systems.
I hope, now the idea of classes and objects is clear to you.
Define Classes and Objects in Python
Here, we will learn how to define classes and objects in python. We will take the instance of Employee Dataset to implement a real-world problem in programming.Ā
Define an Empty Class
First, we will create an empty class named āEmployeeā.
class Employee:
pass
Define an Object of a Class
Defining an object of a class is pretty straightforward. Here is an example.Ā
class Employee:
pass
obj = Employee()
The `__init__` Method
We have seen how to create an object of a class. Here, we will talk about Constructor in Python. In simple, a constructor is a special method in object-oriented programming that is used to initialize objects of a class. When an object is created, the constructor is called automatically and is used to set the initial values of the objectās attributes. The constructor typically takes arguments that correspond to the attributes of the object being created.
In most object-oriented programming languages, the name of the constructor method is the same as the name of the class. In python, the ā__init__ā method plays the role of a constructor. We must provide the āselfā as the first parameter to the ā__init__ā method. It represents the instance of the current class and it allows to access all the attributes and methods defined within that class.
Letās understand the whole concept through an example.
class Employee:
def __init__(self):
self.id = "101124"
self.name = "David"
self.surname = "Jones"
self.age = 32
self.contact = "1234567890"
self.address = "Illinois"
self.designation = "Project Manager"
obj = Employee()
print("ID:",obj.id)
print("Name:",obj.name)
print("Surname:",obj.surname)
print("Age:",obj.age)
print("Contact:",obj.contact)
print("Address:",obj.address)
print("Designation:",obj.designation)
Output
ID: 101124
Name: David
Surname: Jones
Age: 32
Contact: 1234567890
Address: Illinois
Designation: Project Manager
Define more methods inside a class
In the previous example, we declared the ā__init__ā method to store attribute values and printed that data from outside of the class using the class object.
Here, we will delegate the printing task to a function. We will define a different method within the āEmployeeā class to print the data of those attributes separately.
class Employee:
def __init__(self):
self.id = "101124"
self.name = "David"
self.surname = "Jones"
self.age = 32
self.contact = "1234567890"
self.address = "Illinois"
self.designation = "Project Manager"
def display(self):
print("ID:",obj.id)
print("Name:",obj.name)
print("Surname:",obj.surname)
print("Age:",obj.age)
print("Contact:",obj.contact)
print("Address:",obj.address)
print("Designation:",obj.designation)
obj = Employee()
obj.display()
Output
ID: 101124
Name: David
Surname: Jones
Age: 32
Contact: 1234567890
Address: Illinois
Designation: Project Manager
Pass arguments to a class method
So far, we were mentioning the āselfā keyword inside a class method to let the program know that it belongs to that class. Now we will pass additional arguments to a class method. To do so, we must declare corresponding parameters while declaring the method.
As you saw earlier, we stored the values of the variables inside the ā__init__ā method. Here, weāll pass those values as arguments to the ā__init__ā method instead of following the previous method.
class Employee:
def __init__(self, id, name, surname, age, contact, address, desig):
self.id = id
self.name = name
self.surname = surname
self.age = age
self.contact = contact
self.address = address
self.designation = desig
def display(self):
print("ID:",obj.id)
print("Name:",obj.name)
print("Surname:",obj.surname)
print("Age:",obj.age)
print("Contact:",obj.contact)
print("Address:",obj.address)
print("Designation:",obj.designation)
obj = Employee("101124", "David", "Jones", 32,
"1234567890", "Illinois", "Project Manager")
obj.display()
Output
ID: 101124
Name: David
Surname: Jones
Age: 32
Contact: 1234567890
Address: Illinois
Designation: Project Manager
Private members
In Object-Oriented Programming, āprivate membersā refer to the attributes or methods of a class that are only accessible within the class itself, and not from outside the class. Private members are often used to encapsulate implementation details and prevent external code from directly accessing or modifying the internal state of an object.
To declare private members in python, we use a naming convention that indicates that the member is intended to be private (In C++ we use a visibility modifier such as āprivateā), such as a leading underscores (two underscores before).
class MyClass:
def __init__(self):
self.__private_attribute = 48
def __private_method(self):
print("This is a private method")
def public_method(self):
print("This is a public method")
self.__private_method()
obj = MyClass()
obj.public_method()
Output
This is a public method
This is a private method
In this example, the attribute ā__private_attributeā and method ā__private_methodā are declared as private using the leading underscores naming convention. This means that they are intended to be used only within the āMyClassā class and are not intended to be accessed from outside the class.
The āpublic_methodā, on the other hand, is a method that can be accessed from outside the class. It can also access the private attribute and method of the class, but only from within the class.
Using private members in Object-Oriented Programming helps to enforce the principle of encapsulation, which means that the internal state of an object is hidden from external code and can only be accessed and modified through a defined set of methods or functions. This helps to create more robust and maintainable code by preventing unintended access or modification of the internal state of objects.
Encapsulation
Data encapsulation in Object-Oriented Programming (OOP) refers to the practice of hiding the implementation details of an objectās data (attributes) and behavior (methods) from the outside world and providing a public interface for interacting with the object.
Encapsulation is one of the fundamental principles of OOP and is used to protect the internal state of an object from being modified by code outside of the objectās methods. This helps to ensure that the objectās data is always in a valid state and helps to prevent unintended side effects that can occur when code directly manipulates an objectās data.
To achieve encapsulation in OOP, attributes of an object are typically marked as private or protected, which means they can only be accessed and modified by the objectās own methods or by methods of derived classes (in the case of protected attributes). The objectās methods provide a public interface for interacting with the object, which can be used to read and modify the objectās attributes in a controlled and safe way.
For example, consider a class representing a bank account. The balance attribute should be kept private to prevent outside code from directly modifying it, which could lead to inconsistencies in the accountās state. Instead, the class should provide public methods such as ādepositā and āwithdrawā that can update the balance in a controlled way.
Here is an example of Encapsulation in Python.
class BankAccount:
def __init__(self):
# __balance is private
self.__balance = 0
def deposit(self, amount):
self.__balance += amount
def withdraw(self, amount):
if self.__balance >= amount:
self.__balance -= amount
else:
print("Insufficient funds")
def get_balance(self):
return self.__balance
obj = BankAccount()
obj.deposit(54000)
obj.deposit(28000)
print(obj.get_balance())
obj.withdraw(8250)
print(obj.get_balance())
Output
82000
73750
In this example, the double underscores before the attribute name makes it private. This means that the balance attribute cannot be accessed or modified directly from outside the āBankAccountā class. Instead, the class provides public methods such as ādepositā, āwithdrawā, and āget_balanceā that can access and modify the balance attribute in a controlled way.
Abstraction
Data abstraction in object-oriented programming (OOP) refers to the process of simplifying complex systems by breaking them down into smaller, more manageable parts, and modeling those parts as objects.
Abstraction is one of the fundamental principles of OOP and is used to reduce the complexity of a system by hiding unnecessary details and focusing on the essential features. Abstraction allows programmers to create models of real-world systems that can be easily understood, maintained, and modified over time.
In OOP, abstraction is achieved by defining classes that encapsulate both data (attributes) and behavior (methods), and by creating objects that represent instances of those classes. The objects provide a simplified, abstract view of the system, and their methods provide a way to interact with the system in a controlled and meaningful way.
Abstraction is important for creating modular and reusable code, as it allows for the creation of classes and objects that can be used in a wide range of contexts without requiring detailed knowledge of their internal workings. Abstraction also helps to reduce the coupling between different parts of a system, which makes it easier to modify and extend the system over time without causing unintended side effects.
Here is an example, that represents Abstraction in Python.
class Adder:
def __init__(self):
self.__total = 0
def addNumber(self, number):
self.__total += number
def getTotal(self):
return self.__total
if __name__ == "__main__":
obj = Adder()
obj.addNumber(14)
obj.addNumber(22)
obj.addNumber(15)
print(f"Total: {obj.getTotal()}")
In the above example, we declared the ā__totalā variable as private which is accessible only through its own class member functions, and in the end, we applied this technique to print the result.
Inheritance
In object-oriented programming (OOP), inheritance is a mechanism that allows a new class (the āderivedā or āsubclassā) to be based on an existing class (the ābaseā or āsuper classā). Inheritance enables a derived class to inherit the properties and behaviors of the base class, while also allowing the derived class to override or extend those properties and behaviors as needed.Ā
When a subclass is derived from a super class, it automatically inherits all the public and protected properties and methods of the super class. The subclass can then modify or extend those properties and methods, or add new ones of its own.
Consider a real-life situation in which a child inherits some of the parentās characteristics at birth. For example, a mother has blonde hair. Thatās why her child also has blonde hair. There could be many more such examples.
Now come to the point of overriding. The child can modify the derived characteristics (For example, he/she can change the color of his/her hair from blonde to something else) or add more.
Inheritance is the mechanism through which we can translate this real-life relationship between child and mother into programming.
Here is an example, that represents Inheritance in Python.
# Parent Class
class Mother:
def __init__(self):
self.name = "Julia"
self.age = "35"
self.height = "5.4"
self.blood = "O+"
self.hair = "blonde"
self.eye = "brown"
# Child Class
class Daughter(Mother):
def __init__(self):
# Inheriting an instance of Mother Class
Mother.__init__(self)
self._name = "Nancy"
self._age = "8"
self._height = "4.1"
self._blood = "A+"
# Storing a field value of Mother Class
self._hair = self.hair
self._eye = "black"
def printResult(self):
print("Name:",self._name)
print("Age:",self._age)
print("Height:",self._height)
print("Blood:",self._blood)
print("Hair:",self._hair)
print("Eye:",self._eye)
obj = Daughter()
obj.printResult()
Output
Name: Nancy
Age: 8
Height: 4.1
Blood: A+
Hair: blonde
Eye: blackĀ
Inheritance is a key concept in OOP because it enables code reuse and promotes a hierarchical structure for classes, making the code easier to understand and maintain. It also allows for polymorphism, which means that objects of the derived class can be treated as objects of the base class, making the code more flexible and adaptable.
Polymorphism
In object-oriented programming (OOP), polymorphism refers to the ability of different objects to be treated as if they are of the same type, even if they are actually instances of different classes. Polymorphism allows code to be written in a way that is more generic and flexible, making it easier to reuse and maintain.
There are two main types of polymorphism in OOP: Compile-time (or static) polymorphism and Runtime (or dynamic) polymorphism.Ā
Compile-time Polymorphism is achieved through Method Overloading (More details below), which allows multiple methods in a class to have the same name but different parameters. When the method is called, the compiler selects the appropriate version of the method based on the arguments passed.Ā
Runtime Polymorphism, on the other hand, is achieved through Method Overriding (More details below), which occurs when a subclass provides its own implementation of a method that is already defined in the super class. When the method is called on an object of the subclass, the overridden method in the subclass is executed instead of the original method in the super class.
Here is an example of Polymorphism in Python.
# 'Bird' is Super class
class Bird:
def Parent(self):
print("Parent: Bird Class")
def flying(self):
print("Most birds can fly")
# Subclass of 'Bird' class
class Owl(Bird):
def __init__(self):
print("This is Owl Class")
def flying(self):
print("Owls can fly")
# Subclass of 'Bird' class
class Penguin(Bird):
def __init__(self):
print("This is Penguin Class")
def flying(self):
print("Penguins can't fly")
obj = Owl()
obj.flying()
obj.Parent()
In the above example, āBirdā is the parent class. āOwlā and āPenguinā are child or sub classes and each subclass provides its own implementation of a method that is already defined in the parent or super class āBirdā.
Method Overloading
Method Overloading is a feature in object-oriented programming that allows a class to have multiple methods with the same name but different parameters. This means that you can define several methods with the same name in a class, as long as each method takes different types or numbers of parameters.
When a method is called, the compiler determines which method to execute based on the number and types of arguments passed. The appropriate method is selected at compile-time and the appropriate method code is executed at runtime.
For example, consider a class that has a method called ācalculateAreaā. This method can be overloaded to accept different parameters such as the length and width of a rectangle, the radius of a circle, or the base and height of a triangle. Each method would have the same name ācalculateAreaā, but a different parameter list.
Here is an example, that represents Method Overloading in Python.
class Calculation:
def addition(self, a, b, c = 0):
print(a + b + c)
obj = Calculation()
obj.addition(5, 7)
obj.addition(4, 18, 6)
Output
12
28
In the above example, the function āadditionā is called two times with different arguments. On the other side, the function is implemented just once with their parameters where c is set to zero (0) by default.
Another way to implement the method is to use *args. This is the most efficient way because in this case, you can pass any number of arguments to the function instead of following the constraint. Here is an example.
class Calculation:
def addition(self, *args):
result = 0
for num in args:
result += num
print(result)
obj = Calculation()
obj.addition(5, 7)
obj.addition(4, 18, 6)
obj.addition(6, 19, 8, 4)
Output
12
28
37
Note that, method overloading is different from method overriding, where a subclass provides a specific implementation of a method that is already provided by its parent class.
Method Overriding
Method Overriding is a feature in object-oriented programming that allows a subclass to provide a specific implementation of a method that is already provided by its parent class. In other words, when a method in a subclass has the same name, return type, and parameter list as a method in its parent class, the subclass method is said to override the parent class method.
When a method is called on an instance of the subclass, the method in the subclass is executed instead of the method in the parent class. This allows the subclass to provide its own implementation of the method that is more specific to its needs.
class Animal:
def makeSound(self):
print("Animals make sound")
class Cat(Animal):
def makeSound(self):
print("Meow")
obj = Cat()
obj.makeSound()
Output
Meow
In the above example, the āCatā class extends the āAnimalā class and overrides its āmakeSoundā method. When the āmakeSoundā method is called on an instance of the āCatā class, the overridden method in the āCatā class is executed instead of the method in the āAnimalā class.
Summary
In this tutorial, our topic of discussion was Object-Oriented Programming through Python Programming. We covered every key concept related to Object-Oriented Programming and many more.
A quick recap:
- Concept of Object-Oriented Programming
- Defining classes and objects in python (with various programming examples)
- Encapsulation
- Abstraction
- Inheritance
- Polymorphism
- Method Overloading
- Method Overriding
Object-Oriented programming enables code to be written in a more generic and reusable way, making it easier to maintain and update. This allows for more flexible and adaptable code generation, which can be particularly useful in large, complex software systems.
The invention of Object-Oriented Programming is a boon to the world of programming but did you know OOP is a more recent development than procedural programming? It was first developed in the early 1970s, but it did not become popular until the late 1980s.