Skip to main content

Pillar 3: Encapsulation

The Third Pillar of Object-Oriented Programming is Encapsulation.

Encapsulation means bundling data (attributes) and methods together inside a single class container while restricting direct, unauthorized external access to sensitive variables.


1. Learning Objective

By the end of this lesson, you will understand:

  • Why exposing public attributes directly (account.balance = -9999) is dangerous.
  • How to define Private Attributes in Python using double underscores (__attribute).
  • How Python's internal Name Mangling mechanism works in memory.
  • How to use Getters and Setters with validation to protect object integrity.

2. Why This Concept Exists

Imagine a Banking System where anyone can write:

account = BankAccount("Sai", 5000)

# Unrestricted Public Access (DANGEROUS!)
account.balance = -9999999

Without Encapsulation, external code can corrupt internal object data without validation or security checks.

Encapsulation acts as a protective shield around an object's internal state. It forces external code to pass through approved Getter and Setter methods that validate inputs before making modifications.


3. Common Beginner Confusions

Confusion 1: "Is double underscore __balance truly 100% private in Python?"

  • Answer: Conceptually yes, but physically in Python memory, Python uses Name Mangling. Adding double underscores transforms __balance into _ClassName__balance (e.g., _BankAccount__balance). Python does this to prevent accidental overrides, but it respects developer maturity ("We are all consenting adults here").

Confusion 2: "What is the difference between single underscore _var and double underscore __var?"

  • Answer:
    • Single Underscore _var (Protected Convention): Hints to other developers: "This is internal; please don't touch it directly." Python does NOT mangle the name.
    • Double Underscore __var (Private Name Mangling): Python actively mangles the name in memory, raising an AttributeError if accessed directly via obj.__var.

4. Mental Model: ATM Machine Vault Keypad

Think of Encapsulation using the ATM Machine analogy:

  • Inside the Vault (__balance): The cash vault inside an ATM is private data. Bank customers are not allowed to open the vault door with a crowbar to grab cash directly (account.__balance).
  • The ATM Screen & Keypad (Getters/Setters): You must interact with approved, validated methods:
    • get_balance() → Checks your PIN and reads the screen.
    • deposit(amount) → Checks if amount > 0 before adding cash to the vault.

5. Internal Python Execution Flow

Let's trace how Python mangles private attribute names in memory:

Code Executed: self.__balance = balance (inside class BankAccount)

↓ Name Mangling Trace:

1. Python sees double underscore prefix '__' before attribute name 'balance'.
2. Python inspects current class name -> 'BankAccount'.
3. Python rewrites key name into: _BankAccount__balance.
4. Python stores value 5000 inside _BankAccount__balance on Heap Object.
5. If external code calls account.__balance:
- Python looks for key '__balance' -> Not Found!
- Raises AttributeError: 'BankAccount' object has no attribute '__balance'.

6. Memory Visualization: Private Name Mangling Layout

RAM Layout: Protected Private Attribute (Name Mangling)

EXTERNAL DIRECT ACCESS

account.__balance
❌ AttributeError! (Key '__balance' hidden)

HEAP OBJECT (Address 0xC100)

owner: "Sai" (Public)
_BankAccount__balance: 5000 (Mangled Private)


7. Python Code Implementation

class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self.__balance = balance # Private Attribute (Name Mangled)

# 1. Getter Method: Controlled Read Access
def get_balance(self):
return self.__balance

# 2. Setter Method: Controlled Write Access with Input Validation
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"Deposited ₹{amount}. New Balance: ₹{self.__balance}")
else:
print("Error: Deposit amount must be positive!")

def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"Withdrew ₹{amount}. Remaining Balance: ₹{self.__balance}")
else:
print("Error: Invalid transaction or Insufficient Funds!")


# --- Execution ---
acc = BankAccount("Sai", 5000)

# Attempting direct private access:
# print(acc.__balance) # Raises AttributeError!

# Controlled Read via Getter
print("Current Balance:", acc.get_balance())

# Controlled Write via Setter (Validation Success)
acc.deposit(1500)

# Controlled Write via Setter (Validation Failure)
acc.deposit(-500)
acc.withdraw(10000)

Output:

Current Balance: 5000
Deposited ₹1500. New Balance: ₹6500
Error: Deposit amount must be positive!
Error: Invalid transaction or Insufficient Funds!

8. Line-by-Line Execution Analysis

Line: self.__balance = balance

  • Name Mangling: Python internally transforms __balance into _BankAccount__balance on Heap object.

Line: acc.deposit(-500)

  • Validation Defense: Setter method checks if amount > 0. Since -500 > 0 is False, the invalid deposit is rejected, preserving internal data integrity.

9. Before / After Direct Access vs Encapsulated Access

Unencapsulated (Public Attribute)

acc.balance = -500 # Object data corrupted instantly!

Encapsulated (Private Attribute + Setter)

acc.deposit(-500) # Validation fails: "Error: Amount must be positive!" Data remains safe.

10. Illustration Prompt for Diagram Generation

Excalidraw Diagram Prompt: A hand-drawn diagram illustrating Encapsulation and Name Mangling in Python. Draw a thick circular shield boundary labeled "Class BankAccount (Encapsulation Boundary)". Inside the shield, draw a locked safe box labeled "Private Attribute: __balance (Mangled to _BankAccount__balance = 5000)". On the outside of the shield, draw an unauthorized user arrow labeled "acc.__balance" hitting the shield wall and bouncing off with a red "AttributeError" collision spark. Draw two approved door keypads labeled "get_balance()" and "deposit(amount)" with green arrows passing through validation checkpoints into the safe box. White background, clean hand-drawn style, colors: Red (Blocked Access), Green (Approved Gateways), Blue (Shield Boundary).


Quick Summary

  • Encapsulation bundles data and methods while restricting direct external access to sensitive attributes.
  • Use double underscores __attribute to make attributes private.
  • Python protects private attributes via Name Mangling (_ClassName__attribute).
  • Getters and Setters provide controlled, validated interfaces to read and update private object data safely.

What's Next?