Encapsulation in Python
Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP) in Python. It is used to restrict direct access to variables and methods, preventing accidental modifications. Encapsulation helps in data hiding, security, and modularity.
Understanding Encapsulation
Encapsulation involves wrapping data (variables) and methods (functions) within a class and controlling their accessibility. In Python, we achieve encapsulation using:
- Public members (accessible anywhere)
- Protected members (accessible within the class and subclasses, indicated by a single underscore
_
) - Private members (accessible only within the class, indicated by double underscores
__
)
Why Use Encapsulation?
- **Data Protection** – Prevents direct modification of sensitive data.
- **Better Code Organization** – Groups related data and methods.
- **Controlled Access** – Defines how data should be used.
Examples
1. Public Members in a Class
In this example, we define a class with a public variable and access it directly.
We create a Car
class with a public attribute brand
. Since it is public, we can access and modify it outside the class.
class Car:
def __init__(self, brand):
self.brand = brand # Public attribute
# Create an object of Car
my_car = Car("Toyota")
# Access and modify the public attribute
print(my_car.brand) # Output: Toyota
my_car.brand = "Honda"
print(my_car.brand) # Output: Honda
Output
Toyota
Honda
2. Protected Members in a Class
In Python, protected members are indicated by a single underscore _
. They can still be accessed, but it’s a convention that they shouldn’t be modified outside the class.
We create a BankAccount
class with a protected attribute _balance
. Although we can access it outside the class, it is intended to be used only within the class or subclasses.
class BankAccount:
def __init__(self, balance):
self._balance = balance # Protected attribute
def get_balance(self):
return self._balance # Method to access balance
# Create an object
account = BankAccount(5000)
# Accessing the protected attribute (not recommended)
print(account._balance) # Output: 5000
# Accessing balance via a method (preferred way)
print(account.get_balance()) # Output: 5000
Output
5000
5000
3. Private Members in a Class
Private members are indicated by a double underscore __
. They are not accessible directly outside the class.
Here, we create a Person
class with a private attribute __age
.
When we try to access this private attribute __age
directly, results in an error.
class Person:
def __init__(self, age):
self.__age = age # Private attribute
def get_age(self):
return self.__age # Method to access private attribute
# Create an object
person = Person(30)
# Attempting direct access (will cause error)
print(person.__age) # AttributeError
![](https://www.tutorialkart.com/wp-content/uploads/2025/02/Python-encapsulation-1.png)
But when we try to access this private attribute __age
using a method, everything should be fine.
class Person:
def __init__(self, age):
self.__age = age # Private attribute
def get_age(self):
return self.__age # Method to access private attribute
# Create an object
person = Person(30)
# Accessing via method
print(person.get_age()) # Output: 30
Output
30
4. Name Mangling to Access Private Members
Although private attributes cannot be accessed directly, Python uses name mangling to store them with a modified name. We can access them using the format _ClassName__attribute
, but this is not recommended.
class Employee:
def __init__(self, salary):
self.__salary = salary # Private attribute
# Create an object
emp = Employee(50000)
# Access private attribute using name mangling
print(emp._Employee__salary) # Output: 50000
Output
50000
5. Using Getters and Setters
To follow encapsulation principles, we use getter and setter methods to access and modify private attributes safely.
We create a Student
class where __marks
is private. We define get_marks()
to retrieve the value and set_marks()
to modify it with validation.
class Student:
def __init__(self, marks):
self.__marks = marks # Private attribute
def get_marks(self):
return self.__marks # Getter method
def set_marks(self, new_marks):
if 0 <= new_marks <= 100: # Validation
self.__marks = new_marks
else:
print("Invalid marks! Must be between 0 and 100.")
# Create an object
student = Student(85)
# Accessing marks using getter
print(student.get_marks()) # Output: 85
# Updating marks using setter
student.set_marks(95)
print(student.get_marks()) # Output: 95
# Attempting invalid update
student.set_marks(150) # Output: Invalid marks! Must be between 0 and 100.
Output
85
95
Invalid marks! Must be between 0 and 100.
6. Encapsulation in Real-world Applications
Encapsulation is widely used in large applications for data security and modularity. For example, in banking systems, user account details should not be directly modified; they should be accessed via methods.
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Private attribute
def deposit(self, amount):
self.__balance += amount
def withdraw(self, amount):
if self.__balance >= amount:
self.__balance -= amount
else:
print("Insufficient balance!")
def get_balance(self):
return self.__balance
# Creating an account
account = BankAccount(1000)
account.deposit(500)
print(account.get_balance()) # Output: 1500
Output
1500