1. Home
  2. Docs
  3. Object Oriented Programming in Python
  4. Encapsulation

Encapsulation

In this section you will learn about Encapsulation and Data Abstraction.

Encapsulation is one of the three pillars of Object Oriented Programming.

The OOP relies heavily on encapsulation.

The terms encapsulation and data abstraction are often interchangeable.

Actually, the data abstraction is achieved through encapsulation.

Encapsulation in general, is a mechanism,

to restrict the direct access of some of objects attributes.

That is, to hide internal implementation of an object, from outside its definition.

Typically access to attributes is only allowed, through setters and getters methods.

We have already used encapsulation in our previous lesson,

without emphasizing on the concept, let’s explore it further here.

Recall our MyClass, in this class, we have set() and get()

instance methods to access the attribute of the class.

set() and get() methods are generally referred as setters and getters.

 
class MyClass(object):

    x = 10

    def get(self):

        return self.x
    
    def set(self,value):

        self.x = value

As we have seen in the attributes lesson class or instance attributes can be accessed by using dot notation.

like below,

m1 = MyClass()

m1.x  = 20

Then the question comes, when we access attributes with dot notation why we need setters and getters.

Why setter() and getter() are required ? or why encapsulate?

With the use of get() and set() methods,

We can make sure the attributes are not modified accidentally,

which may lead to inconsistent or invalid state.

With encapsulation we can ensure the integrity of objects data.

Let’s look at an example of why we need setters and getters


class MyNumber(object):
    
    def set(self,value):
        try:
            
            value = int(value)
            
        except ValueError:
            return
        
        self.value = value
            
    def get(self):
        return self.value 
    
    def increment(self):
        
        self.value += 1
        
mn = MyNumber()

# creating an instance

# setter used to set value

mn.set(12)

# getter is used 

print(mn.get())

output:

12

Setting the values directly

You know we can set value directly with dot notation.


# set value directly

mn.value = 30

mn.increment()

print(mn.get())


output:

31

this is as expected, we set a value of 30 and then called increment() method to get 31.

This works fine, for <strong>numeric </strong>value. What if we set a <strong>string </strong>value accidentally. 


# set value directly

mn.value = "Hello"

# call increment instance method

mn.increment()

output:


---------------------------------------------------------------
TypeError                     Traceback (most recent call last)
<ipython-input-13-61ccc6223a42> in <module>()
     30 # call increment instance method
     31 
---> 32 mn.increment()
     33 
     34 

<ipython-input-13-61ccc6223a42> in increment(self)
     16     def increment(self):
     17 
---> 18         self.value += 1
     19 
     20 mn = MyNumber()

TypeError: must be str, not int


You will be presented with a TypeError.

This is known as breaching the data integrity.

We tried to set a inconsistent data.

Using setter to set the values

What if we use set() method to set inconsistent data, lets check


mn.set("Hello") 

mn.increment()

print(mn.get())


output:

13

as the setter validates the input and discards invalid values.

the data integrity is maintained, and no error is thrown.

Encapsulation ensures safe storage of data in an instance.

As a best practice attributes should always be accessed,

by setter and getter instance methods.

In the next lesson you learn about another important concept Inheritance.