Introduction

Encapsulation is an important aspect of object-oriented programming and plays a crucial role in building complex software systems. At its core, encapsulation allows you to control the access to the data and methods of your objects. This results in a more secure, maintainable and efficient code-base. In this tutorial, we'll dive into what encapsulation is all about, how to implement it using Python's various features such as classes, encapsulation techniques, and more. So let's get started!

Table of Contents :

  • What is Encapsulation
  • What is Data hiding
  • Encapsulation vs Data hiding
  • What are Access modifiers
  • Access modifiers in Python
    • Public data members in Python 
    • Private data members in Python 
    • Protected data members in Python 
  • Name Mangling in Python

What is Encapsulation

  • Encapsulation is the process of binding the data and the code that works on that data together.
  • The data members and data functions of a class are encapsulated as one unit.
  • When we define a class in any programming language, we are actually implementing encapsulation.
  • Encapsulation is a way of decreasing and hiding the complexity of the code.
  • Due to encapsulation, the end user of the system can focus more on what to do with the system and not how it is done.
  • An example of encapsulation in real world can be applying the brake of a scooter.
  • When we apply the brake of a scooter - 
    • We only need to know what lever we have to pull to apply brake.
    • We are totally unaware of the internal mechanisms that are taking place when we pull the lever.
    • We do not need to know what wires are being pulled through the lever,  what are the brake shoes doing, how the tires are being stopped etc.
  • This is how encapsulation helps in reducing the complexity of the system.
  • Encapsulation is a sub-process of data hiding.

What is data hiding

  • Data hiding is a very important concept of object oriented programming which is more related to the security of the system.
  • Data hiding protects the data members of a class from unauthorized access by any other code.
  • It is a technique that restricts the access and manipulation of data members of a class from other classes and any other code outside the class.
  • In other words, the data members of a class can be accessed through data functions of that class only.
  • Any outer code do not have access to the data members of this class.
  • In this way Data hiding is a process of ensuring that both data and the code implementation is safe from interference from outside code.
  • The key difference between encapsulation and data hiding is that encapsulation focuses on hiding the complexity of the system whereas data hiding focuses on the security of the system.
  • A simple example of data hiding can be information of our social media accounts - 
    • The outside world can view the non-sensitive information of our social media accounts like name, display pic, status etc.
    • But it cannot see sensitive information like passwords, security question etc. because it would be a big security flaw.
    • Also outside world is not allowed to make changes even to our publicly visible information.
  • This is how data hiding ensures security of the system.
  • We can achieve data hiding by making use of encapsulation along with access modifiers (Discussed in upcoming sections). Hence we can say that encapsulation is a sub-process of Data hiding.

Encapsulation Vs Data Hiding 

Below we present the key differences between encapsulation and data hiding in a tabular form :

Data HidingEncapsulation
Data hiding focuses on system securityEncapsulation focuses on reducing and hiding the complexity of the system
Data hiding is a techniques of securing the data from unauthorized access from outside code.Encapsulation is a technique of wrapping or enveloping the data and functions together as a single unit.
Data hiding is a process and a technique in itself. We can implement data hiding by using encapsulation and access modifiers.Encapsulation is a sub-process of Data hiding.
In Data hiding data is inaccessible from outside code. Depending upon requirement, the data can be made private or protected. In encapsulation data can be public as well. Encapsulation is not concerned about the security of data.

What are Access modifiers 

  • Most object oriented programming languages like Java, c# etc. make use of access modifiers to restrict the access of data members of a class from different parts of the code.
  • Usually there are three access modifiers : 
    • Public : Public members can be accessed from anywhere in the code.
    • Private : Private members can only be accessed from within the same class. 
    • Protected : Protected members can only be accessed from within the same class or from an inherited class. 

Access modifiers in Python

  • Python do not have any privacy model as such.
  • In python we do not have any access modifiers like public, private and protected. 
  • Though we can mimic the functionality of protected and private data members by using underscore and double underscores.
  • Internally it is just a mechanism of avoiding name clashes between members of classes and inherited classes.
  • Note # : Further in the tutorial we'll make use of the terms public, protected and private for python class members as well, but it should be kept in mind that these are not real access modifiers but just emulations. 
  • Public members in python : By default all the members of a class in python are public.
  • Private members in python : A class member can be made private in python by adding double underscore in front of its name. In practice adding a double underscore invokes name mangling (discussed in the upcoming section).
  • Protected members in python : We can make a class member protected by adding single underscore in front of its name.

Public data members in Python 

  • In the code sample given below we'll take a look at how public data members work in python. 
  • In the code sample the  Car  class has three data members :  make model , and  year
  • These variables are public, which means they can be accessed from outside the class. 
  • Code Sample : 

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.year = year


car = Car("Audi", "Q7", 2023)

# Accessing data members from outside the class
print(f"The make of the car is : {car.make}")
print(f"The model of the car is : {car.model}")
print(f"The year of the car is : {car.year}")


# Output
# The make of the car is : Audi
# The model of the car is : Q7
# The year of the car is : 2023



  • Explanation :
  • As we can see in the code above - the data members can be printed from code outside the class  Car .
  • In other words we can say that public data members can be accessed from outside the class.

Private data members in Python 

  • Now we declare the  year  data member as private
  • We can emulate this by adding a double underscore character   __   before the variable name. 
  • The syntax of doing this is :  __data-member-name 
  • We know that private data members are visible only within the class and are hidden from the outside code.
  • Code Sample : 

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.__year = year

    def show_year(self):
        print()
        print("Printing the year from within the class")
        print(f"The year of the car is : {self.__year}")
        print()


car = Car("Audi", "Q7", 2023)
car.show_year()

# Accessing data members from outside the class
print(f"The make of the car is : {car.make}")
print(f"The model of the car is : {car.model}")
print(f"The year of the car is : {car.__year}")


# Output
# Printing the year from within the class
# The year of the car is : 2023

# The make of the car is : Audi
# The model of the car is : Q7
# AttributeError: 'Car' object has no attribute '__year' 


  • Explanation :
  • In the code sample above we have declared the  __year  variable as private 
  • This means that  __year  variable can only be accessed from within the  Car  class. 
  • The output clearly shows that 
    • When we access the  __year  variable from within the class i.e. by using the instance method of the class, it is printed successfully.
    • But when we try to access the  __year  variable from outside the class an error message is thrown by python interpreter saying :  AttributeError: 'Car' object has no attribute '__year' 
  • This shows that private data members can be accessed from within the class only and are unknown to any code outside the class.

Protected data members in Python 

  • Now we declare the  year  data member as protected
  • We can emulate this by adding a single underscore character   _   before the variable name. 
  • The syntax of declaring a data member as protected is :  _data-member-name 
  • We know that protected data members are visible only within the class and to the inherited classes and are hidden from the outside code.
  • Note # : In real practice protected members in python can be accessed from outside code as well.
  •  In python making a class member protected by using single underscore is just a method of indicating other developers to be responsible enough to not touch these variables from anywhere other than the class itself and the inherited classes.
  • We can use property decorators in python to actually make members of a class protected in Python.
  • Code Sample : 

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self._year = year

    def show_year(self):
        print()
        print("Printing the year from within the class")
        print(f"The year of the car is : {self._year}")
        print()


class ElectricCar(Car):
    def __init__(self, make, model, year):
        super().__init__(make, model, year)


car = Car("Audi", "Q7", 2023)
car.show_year()

# Accessing data members from inherited class
ecar = ElectricCar("Audi", "Q7", 2023)
print(f"The year of the e-car = {ecar._year}")
print()

# Accessing data members from outside code
print(f"The year of the car = {car._year}")

# Output
# Printing the year from within the class
# The year of the car is : 2023

# Printing the year from inherited class
# The year of the e-car = 2023

# Printing the year from outside code
# The year of the car = 2023


  • Explanation :
  • In the code sample above we have declared the  _year  variable as protected.
  • This means that  _year  variable can only be accessed from within the  Car  class and also from any of its inherited class. 
  • The output clearly shows that 
    • When we access the  _year  variable from within the class i.e. by using the instance method of the class, it is printed successfully.
    • When we access the  _year  variable from within the inherited class i.e. by using the instance of the  ElectricCar  class, it is printed successfully.
    • As discussed above the protected members can be accessed from outside code as well in real practice. Single underscore is just an instruction to developers that this variable should be treated as protected and should not be used from outside code.

Name mangling in Python 

  • We know that, the whole process of adding underscores to make class members as private or protected in python is a technique of avoiding name clashes that may happen due to inheritance.
  • When we add double underscore to a class variable in python it is assigned a new name internally.
  • The syntax of the new name is :  _classname__variable 
  •  This renaming makes this variable unavailable outside the class, hence we can treat it as a private class member.
  • This process of renaming the variables with double underscore is called Name mangling in python.
  • We can thus access these private class members from outside the class as well by using the name of the new name of the class member.
  • Code Sample :

class Car:
    def __init__(self, make, model, year):
        self.make = make
        self.model = model
        self.__year = year



car = Car("Audi", "Q7", 2023)

# Accessing data members from outside the class
yr = _Car__year
print(f"The year of the car is : {yr}")


# Output
# The year of the car is : 2023


Next Tutorial : Polymorphism