Encapsulation in python
Encapsulation in Python is one of the core principles of object-oriented programming (OOP). It refers to restricting access to certain components of an object and bundling data (attributes) and methods (functions) that operate on the data into a single unit—a class.
Encapsulation helps in hiding the internal state of objects.
You use getters and setters to access or modify private data safely.
In Python, you can't enforce true private variables like in some other languages, but name mangling (__var) makes it harder to access them directly.
In Python, encapsulation is implemented using access specifiers:
Public: Accessible from anywhere (default).
Protected (_variable): Should not be accessed directly outside the class (a convention).
Private (__variable): Name mangling is used to make attributes harder to access from outside the class.
Example :
class Employee:
def __init__(self, name, salary):
self.name = name # Public
self._position = "Staff" # Protected (convention)
self.__salary = salary # Private
def show_details(self):
print(f"Name: {self.name}")
print(f"Position: {self._position}")
print(f"Salary: {self.__salary}") # Accessing private within class
def set_salary(self, amount):
if amount > 0:
self.__salary = amount
else:
print("Invalid salary amount.")
def get_salary(self):
return self.__salary
# Creating an object
emp = Employee("Alice", 50000)
# Accessing public attribute
print(emp.name) # Alice
# Accessing protected attribute (allowed but not recommended)
print(emp._position) # Staff
# Trying to access private attribute directly
try:
print(emp.__salary) # Error!
except AttributeError as e:
print(e)
# Accessing private attribute through public method
print(emp.get_salary()) # 50000
# Updating private attribute using setter
emp.set_salary(55000)
print(emp.get_salary()) # 55000
Let's take real world example like bank account, where the balance is private attribute and access to control it is using getter and setter method.
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner # Public
self.__balance = balance # Private
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"Deposited ${amount}")
else:
print("Deposit amount must be positive.")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"Withdrew ${amount}")
else:
print("Insufficient funds or invalid amount.")
def get_balance(self):
return self.__balance
def set_balance(self, amount):
if amount >= 0:
self.__balance = amount
else:
print("Balance cannot be negative.")
# Create a BankAccount object
account = BankAccount("John Doe", 1000)
# Access public attribute
print("Account Owner:", account.owner)
# Access private attribute directly (not allowed)
try:
print(account.__balance) # Raises AttributeError
except AttributeError as e:
print("Error:", e)
# Proper way to access balance
print("Initial Balance:", account.get_balance())
# Make some transactions
account.deposit(500)
account.withdraw(300)
print("Current Balance:", account.get_balance())
# Try to set a negative balance
account.set_balance(-100) # Should show error