Encapsulation
An objects variables should not always be directly accessible.
To prevent accidental change, an objects variables can sometimes only be changed with an objects methods. Those type of variables are private variables.
Important Note:
In C++ and Java, things are pretty straight-forward. There are 3 magical and easy to remember access modifiers, that will do the job (public, protected and private). But there’s no such a thing in Python. That might be a little confusing at first, but it’s possible too. We’ll have look at how do it right in Python.
Python doesn’t have any mechanisms, that would effectively restrict you from accessing a variable or calling a member method. All of this is a matter of culture and convention. In PYTHON, we can easily bypass protected/private variables/methods.
Protected Variables
Private Variables
Protected Methods
Private Methods
Protected Variables:
Protected members (in C++ and JAVA) are those members of the class which cannot be accessed outside the class but can be accessed from within the class and it’s subclasses. To accomplish this in Python, just follow the convention by prefixing the name of the member by a single underscore “_”.
# Creating a base class
class Base:
def __init__(self):
# Protected member
self._a = 2
# Creating a derived class
class Derived(Base):
def __init__(self):
# Calling constructor of
# Base class
Base.__init__(self)
print("Calling protected member of base class: ")
print(self._a)
obj1 = Base()
# Calling protected member
# Outside class will result in
# AttributeError
print(obj1.a)
obj2 = Derived()
AttributeError Traceback (most recent call last)
in 25 # Outside class will result in 26 # AttributeError ---> 27 print(obj1.a) 28 29 obj2 = Derived()
AttributeError: 'Base' object has no attribute 'a'
Bypassing Protected Variable
Example 2:
# Creating a base class
class Base:
def __init__(self):
# Protected member
self._a = 2
# Creating a derived class
class Derived(Base):
def __init__(self):
# Calling constructor of
# Base class
Base.__init__(self)
print("Calling protected member of base class: ")
print(self._a)
obj1 = Base()
print(obj1._a)
obj2 = Derived()
2
Calling protected member of base class:
2
Python doesn’t have any mechanisms, that would effectively restrict you from accessing a variable or calling a member method. All of this is a matter of culture and convention
Private Variable
Example 1
# Creating a base class
class Base:
def __init__(self):
self.__a = 2
# Creating a derived class
class Derived(Base):
def __init__(self):
Base.__init__(self)
print("Calling private member of base class will give error")
print(self.__a)
obj1 = Base()
print(obj1.a)
obj2 = Derived()
AttributeError Traceback (most recent call last)
in 14 obj1 = Base() 15 ---> 16 print(obj1.a) 17 18 obj2 = Derived()
AttributeError: 'Base' object has no attribute 'a'
ByPassing Private Variable
Example 2:
# Creating a base class
class Base:
def __init__(self):
self.__a = 2
# Creating a derived class
class Derived(Base):
def __init__(self):
Base.__init__(self)
print("Calling private member of base class will give error")
print(self.__a)
obj1 = Base()
print(obj1._Base__a)
obj2 = Derived()
2
Calling private member of base class will give error
2
Protected Method:
Example 1:
class Car:
def __init__(self):
self._updateSoftware()
def drive(self):
print('driving')
def _updateSoftware(self):
print('updating software')
redcar = Car()
redcar.drive()
redcar.updateSoftware()
updating software
driving
AttributeError Traceback (most recent call last)
in 12 redcar = Car() 13 redcar.drive() ---> 14 redcar.updateSoftware()
AttributeError: 'Car' object has no attribute 'updateSoftware'
ByPassing Protected Method:
class Car:
def __init__(self):
self._updateSoftware()
def drive(self):
print('driving')
def _updateSoftware(self):
print('updating software')
redcar = Car()
redcar.drive()
redcar._updateSoftware()
updating software
driving
updating software
Private Method:
class Car:
def __init__(self):
self.__updateSoftware()
def drive(self):
print('driving')
def __updateSoftware(self):
print('updating software')
redcar = Car()
redcar.drive()
redcar.__updateSoftware()
updating software
driving
AttributeError Traceback (most recent call last)
in 12 redcar = Car() 13 redcar.drive() ---> 14 redcar.__updateSoftware()
AttributeError: 'Car' object has no attribute '__updateSoftware'
Bypassing Private Method:
class Car:
def __init__(self):
self.__updateSoftware()
def drive(self):
print('driving')
def __updateSoftware(self):
print('updating software')
redcar = Car()
redcar.drive()
redcar._Car__updateSoftware()
updating software
driving
updating software
Encapsulation example
Python does not have the private keyword, unlike some other object oriented languages, but encapsulation can be done.
Instead, it relies on the convention: a class variable that should not directly be accessed should be prefixed with an underscore.
Example 1:
class Robot(object):
def __init__(self):
self.a = 123
self._b = 123
self.__c = 123
obj = Robot()
print(obj.a)
print(obj._b)
print(obj.__c)
123
123
Traceback (most recent call last):
File "test.py", line 10, in <module>
print(obj.__c)
AttributeError: 'Robot' object has no attribute 'c'
So what’s with the underscores and error?
A single underscore: Private variable, it should not be accessed directly. But nothing stops you from doing that (except convention).
A double underscore: Private variable, harder to access but still possible.
Both are still accessible: Python has private variables by convention.
Getters and setters
Private variables are intended to be changed using getter and setter methods. These provide indirect access to them:
Example 2:
class Robot(object):
def __init__(self):
self.__version = 22
def getVersion(self):
print(self.__version)
def setVersion(self, version):
self.__version = version
obj = Robot()
obj.getVersion()
obj.setVersion(23)
obj.getVersion()
print(obj.__version)
This then outputs the variables values:
22
23
23
Example 3 :
#!/usr/bin/python3
class JustCounter:
__secretCount = 0
def count(self):
self.__secretCount += 1
print (self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print (counter._JustCounter__secretCount)
print (JustCounter._JustCounter__secretCount)
print (counter.__secretCount)
1
2
2
0
AttributeError Traceback (most recent call last)
<ipython-input-32-0677a9635e82> in <module>
in 13 print (counter._JustCountersecretCount)
14 print (JustCounter._JustCountersecretCount)
---> 15 print (counter.__secretCount)
AttributeError: 'JustCounter' object has no attribute '__secretCount'
Example 4:
class MyClass:
# Hidden member of MyClass
__hiddenVariable = 0
# A member method that changes
# __hiddenVariable
def add(self, increment):
self.__hiddenVariable += increment
print (self.__hiddenVariable)
# Driver code
myObject = MyClass()
myObject.add(2)
myObject.add(5)
# This line causes error
print (myObject.__hiddenVariable)
2
7
Traceback (most recent call last):
File "filename.py", line 13, in
print (myObject.hiddenVariable)
AttributeError: MyClass instance has no attribute 'hiddenVariable'
In the above program, we tried to access hidden variable outside the class using object and it threw an exception.
We can access the value of hidden attribute by a tricky syntax:
# A Python program to demonstrate that hidden
# members can be accessed outside a class
class MyClass:
# Hidden member of MyClass
__hiddenVariable = 10
# Driver code
myObject = MyClass()
print(myObject._MyClass__hiddenVariable)
10
Example 6:
class MyClass:
# Hidden member of MyClass
__hiddenVariable = 0
# A member method that changes
# __hiddenVariable
def add(self, increment):
self.__hiddenVariable += increment
print (self.__hiddenVariable)
# Driver code
myObject = MyClass()
myObject.add(2)
myObject.add(5)
print (myObject._MyClass__hiddenVariable)
print (MyClass._MyClass__hiddenVariable)
2
7
7
0
Last updated
Was this helpful?