OOP Concepts · Lesson 2 of 8 · Updated ·
Encapsulation and Abstraction — The Difference, Explained Simply
These two pillars are often confused. In one line each:
- Encapsulation = protect the data (keep it private; allow access only through methods).
- Abstraction = hide the complexity (users see a simple interface, not the inner workings).
1. Encapsulation
Without encapsulation, any code could write account.balance = -500. With it, the class guards its own rules.
class BankAccount:
def __init__(self, owner):
self.owner = owner
self.__balance = 0 # double underscore: name-mangled, "private"
def deposit(self, amount):
if amount <= 0:
raise ValueError("deposit must be positive")
self.__balance += amount
def withdraw(self, amount):
if amount > self.__balance:
return "Insufficient balance"
self.__balance -= amount
return f"Withdrew {amount}"
@property
def balance(self): # read-only access
return self.__balance
acc = BankAccount("Asha")
acc.deposit(1000)
print(acc.withdraw(300), acc.balance)
print(acc.withdraw(5000))
try:
acc.__balance = -500 # creates a NEW attribute; the real balance is safe
print(acc.balance)
except AttributeError as e:
print(e)
Withdrew 300 700
Insufficient balance
700
Java does it with the private keyword and getters/setters:
class Student {
private int marks; // hidden
public int getMarks() { return marks; }
public void setMarks(int m) {
if (m < 0 || m > 100) throw new IllegalArgumentException("marks must be 0-100");
marks = m;
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student();
s.setMarks(88);
System.out.println(s.getMarks());
try {
s.setMarks(150);
} catch (IllegalArgumentException e) {
System.out.println("Rejected: " + e.getMessage());
}
}
}
88
Rejected: marks must be 0-100
Benefits: data stays valid, internal code can change without breaking users, easier debugging (only one place changes the data).
2. Abstraction
Abstraction is about design: what should users of this class see? In code, it's usually done with abstract classes or interfaces that define what must be done, leaving how to the concrete classes.
from abc import ABC, abstractmethod
class Notifier(ABC):
@abstractmethod
def send(self, to, text):
"""Every notifier must know how to send."""
class SmsNotifier(Notifier):
def send(self, to, text):
return f"SMS to {to}: {text}"
class EmailNotifier(Notifier):
def send(self, to, text):
return f"Email to {to}: {text}"
def remind(notifier: Notifier, to):
# this function doesn't know or care HOW the message goes out
return notifier.send(to, "Your mock test starts at 6 pm")
print(remind(SmsNotifier(), "98290xxxxx"))
print(remind(EmailNotifier(), "asha@x.in"))
try:
Notifier()
except TypeError:
print("Can't create an abstract Notifier")
SMS to 98290xxxxx: Your mock test starts at 6 pm
Email to asha@x.in: Your mock test starts at 6 pm
Can't create an abstract Notifier
Tomorrow you can add WhatsAppNotifier — remind() doesn't change at all.
3. The difference (interview answer)
| Encapsulation | Abstraction | |
|---|---|---|
| Goal | protect data | hide complexity |
| Question it answers | "who can change this data?" | "what does the user need to see?" |
| How | private fields + methods | abstract classes, interfaces |
| Level | implementation | design |
| Example | balance is private | Notifier.send() hides SMS/email details |
They work together: abstraction decides the public face; encapsulation locks the inside.
Common mistakes
- Saying they're the same thing.
- Making fields private but adding a setter with no checks — that's not real protection.
- Thinking Python has truly private variables (it has conventions:
_xinternal,__xname-mangled).
Quick recap
- Encapsulation: private data + controlled methods → data stays valid.
- Abstraction: expose what, hide how → interfaces/abstract classes.
- Encapsulation is about protection; abstraction is about simplicity.