Python

Encapsulation is one of the fundamental pillars of Object-Oriented Programming (OOP). It describes the idea of wrapping data (attributes) and the methods that work on that data within a single unit, usually a Class.

Beyond just grouping things together, encapsulation is primarily about Information Hiding—restricting direct access to some of an object's components to prevent accidental modification or misuse.

1. Theoretical Overview

The "Black Box" Analogy

Think of a Medicine Capsule. You know the medicine is inside, but you don't interact with the powder directly; you take the capsule. Similarly, a class acts as a protective container that keeps the internal data safe from external interference.

Access Modifiers

Unlike languages like Java or C++, Python does not have strict private or protected keywords. Instead, it uses a naming convention to signal how an attribute or method should be treated:

  1. Public Members: Accessible from anywhere (inside or outside the class).

    • Syntax: name

  2. Protected Members: Should not be accessed outside the class, except by sub-classes (Inheritance).

    • Syntax: _name (single underscore)

  3. Private Members: Strictly accessible only within the class itself.

    • Syntax: __name (double underscore)

Why Use Encapsulation?

  • Data Security: Prevents external code from setting invalid values (e.g., setting a "bank_balance" to a negative number).

  • Flexibility: You can change the internal implementation of a class without affecting the code that uses the class.

  • Control: By using Getter and Setter methods, you can control exactly how data is read or modified.

2. Code Implementation

A. Protecting Data with Private Members

In this example, we protect the __balance attribute so it cannot be changed directly from outside the class.

Python
class BankAccount:
    def __init__(self, owner, balance):
        self.owner = owner          # Public attribute
        self.__balance = balance    # Private attribute (Double underscore)

    # Getter method: To see the balance
    def get_balance(self):
        return f"Account Balance: ${self.__balance}"

    # Setter method: To change the balance with validation
    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"Successfully deposited ${amount}")
        else:
            print("Invalid deposit amount!")

# Usage
account = BankAccount("Arjun", 1000)

print(account.owner)        # Works (Public)
# print(account.__balance)  # Raises AttributeError (Private)

print(account.get_balance()) # Accessing via a controlled method
account.deposit(500)

3. Name Mangling

When you use a double underscore __, Python performs "Name Mangling." It internally changes the name of the variable to _ClassName__variableName. While you can technically still access it this way, it is a strong signal that you shouldn't.

Python
# Technically possible but highly discouraged:
print(account._BankAccount__balance) 

4. Summary Table

Access LevelSyntaxDescription
Publicself.valueAccessible everywhere.
Protectedself._valueAccessible in Class and Sub-classes. (Gentleman's agreement)
Privateself.__valueAccessible only within the defined Class.
Upcoming Course
Upcoming Course
Learn More
Instructor Tips
Instructor Tips
View Tips
Join Community
Join Community
Join Now