Understanding Encapsulation in Python
Introduction
In Object-Oriented Programming (OOP), encapsulation is the concept of wrapping data, and the methods to work as a single cell on the data. Now by doing this, it put restrictions to access variables and methods directly and also can save us from the accidental modification of data. To prevent this change, we can only change an object’s variable by the object’s method. These types of variables are called private variables. A class can be an example of encapsulation, as it encapsulates all the data like variables, members functions, subclasses, etc.
A real-life example of encapsulation
Now let us see an example of real life. Suppose there is a company that consists of many sections like finance section, sales section, accounts section, etc. All sections have their role to play. The finance section handles the finance work of the company and the sales section maintains the sales works of the company. Someday the finance section needs the records of the sales section. Now the finance section can not directly just access the records of the sales section. So in that case, the finance section will ask one o the agents from the sales section to let them access some records that were needed by the finance section. Now, this is what encapsulation i. Here the sales records and the agents working in that section are wrapped in a single unit named as sales section. Also using encapsulation, we can hide data, as in the above example we can see that the employees of the finance section can not access the records or the sales section. So in this section data of a section is hidden from other sections.
Protected members
In Java and C++, the members can not be accessed outside of the class but can be accessed in the class and the subclasses in which it was declared. Now to accomplish this in python, we need to follow a convention, that is by prefixing the member with a single underscore ‘_’.
But this protected variable can be accessed out of the class and also can be accessed in the derived class. It is not a rule but a convention, that not to access the protected class body.
As soon the object of the init method is instantiated the constructor runs. By the way __init__method is a constructor.
Code
class B: def __init__(self): self._a = 2
class D(B): def __init__(self): B.__init__(self) print("Calling protected member: ", self._a) self._a = 3 print("Calling modified protected: ", self._a)
o1 = D()
o2 = B()
print("Accessing protected member of obj1: ", o1._a)
print("Accessing protected member of obj2: ", o2._a) |
Output
Calling modified protected: 3 Accessing protected member of o1: 3 Accessing protected member of o2: 2 |
Private members
In Python, private members are very much like protected members, now the difference between them is the class members of the class declare private can not be accessed outside the class. They also can not be accessed in any of the base classes. In Python, a private instance does not exist, because there is no way that an instance can be private and cannot be accessed. But if you want to declare a member private prefix that member name is with a double “__”.
Code
class C: def __init__(self): self.a = "Board Infinity" self.__c = "Infinite" class D(C): def __init__(self): C.__init__(self) print("Calling private member of base class: ") print(self.__c) # Driver code obj = C() print(obj.a) # If we uncomment print(obj.c), it will # raise an AttributeError
# If we uncomment obj2 = Derived(), it will # raise an AtrributeError because # private member of base class # is called inside derived class |
Output
Board Infinity |
Uncommenting obj.c
class C: def __init__(self): self.a = "Board Infinity" self.__c = "Infinite" class D(C): def __init__(self): C.__init__(self) print("Calling private member of base class: ") print(self.__c) # Driver code obj = C() print(obj.a) print(obj.c)
# obj2 = Derived() |
Output
Board Infinity Traceback (most recent call last): File "main.py", line 16, in <module> print(obj.c) AttributeError: 'C' object has no attribute 'c' |
Uncommenting obj2
class C: def __init__(self): self.a = "Board Infinity" self.__c = "Infinite" class D(C): def __init__(self): C.__init__(self) print("Calling private member of base class: ") print(self.__c) # Driver code obj = C() print(obj.a) # print(obj.c) obj2 = Derived() |
Output
Board Infinity Traceback (most recent call last): File "main.py", line 18, in <module> obj2 = Derived() NameError: name 'Derived' is not defined |