# 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.**

1. Protected Variables
2. Private Variables
3. Protected Methods
4. 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 “\_”**.

```python
# 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)

&#x20;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:

```python
# 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&#x20;

Calling protected member of base class:&#x20;

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

```python
# 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)

&#x20;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:

```python
# 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&#x20;

Calling private member of base class will give error&#x20;

2

**Protected Method:**

Example 1:

```python
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&#x20;

driving&#x20;

AttributeError Traceback (most recent call last)

&#x20;in  12 redcar = Car() 13 redcar.drive() ---> 14 redcar.updateSoftware()

AttributeError: 'Car' object has no attribute 'updateSoftware'

**ByPassing Protected Method:**

```python
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&#x20;

driving&#x20;

updating software

**Private Method:**

```python
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)

&#x20;in  12 redcar = Car() 13 redcar.drive() ---> 14 redcar.\_\_updateSoftware()

AttributeError: 'Car' object has no attribute '\_\_updateSoftware'

**Bypassing Private Method:**

```python
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&#x20;

driving&#x20;

updating software

### &#x20;<a href="#encapsulation-example" id="encapsulation-example"></a>

### Encapsulation example <a href="#encapsulation-example" id="encapsulation-example"></a>

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:

```python
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&#x20;

123&#x20;

Traceback (most recent call last):&#x20;

&#x20;       File "test.py", line 10, in \&lt;module\&gt;

&#x20;               print(obj.\_\_**c)**&#x20;

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:

```python
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 :

```python
#!/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.\_JustCounter**secretCount)**&#x20;

**14 print (JustCounter.\_JustCounter**secretCount)

\---> 15 print (counter.\_\_secretCount)

AttributeError: 'JustCounter' object has no attribute '\_\_secretCount'

Example 4:

```python
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&#x20;

7&#x20;

Traceback (most recent call last):&#x20;

File "filename.py", line 13, in&#x20;

print (myObject.**hiddenVariable)**&#x20;

**AttributeError: MyClass instance has no attribute '**&#x68;iddenVariable'

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:

```python
# 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:

```python
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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gyansetu-python.gitbook.io/python-programming/oops/data-binding-encapsulation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
