Python Encapsulation
$count++; if($count == 1) { include "../mobilemenu.php"; } ?> if ($count == 2) { include "../sharemediasubfolder.php"; } ?>
Encapsulation is an OOP principle that restricts direct access to certain attributes and methods of a class to protect data from unintended modification. Encapsulation allows us to bundle data (attributes) and methods that operate on the data into a single unit (class) while controlling how external code interacts with them.
Python achieves encapsulation through attribute visibility levels: public, protected, and private.
1. Public Attributes and Methods
Attributes and methods in Python are public by default, which means they can be accessed and modified freely from outside the class. This approach is common for attributes that don't require special access control.Example of Public Attributes:
class Car:
def __init__(self, brand, speed):
self.brand = brand # Public attribute
self.speed = speed # Public attribute
def display_info(self): # Public method
return f"Car brand: {self.brand}, Speed: {self.speed}"
car = Car("Toyota", 120)
print(car.display_info()) # Accessing public method
print(car.brand) # Accessing public attribute
Output:
Car brand: Toyota, Speed: 120
Toyota
2. Protected Attributes and Methods
Protected attributes and methods use a single underscore (`_`) prefix, indicating they should not be accessed directly outside the class hierarchy. Although they are technically accessible, by convention, they are intended for internal use within the class and its subclasses.Example of Protected Attributes:
class Vehicle:
def __init__(self, name, speed):
self._name = name # Protected attribute
self._speed = speed # Protected attribute
def _display_info(self): # Protected method
return f"Vehicle name: {self._name}, Speed: {self._speed}"
class Bike(Vehicle):
def bike_info(self):
return self._display_info() # Accessing protected method
vehicle = Vehicle("Truck", 80)
print(vehicle._name) # Accessing protected attribute (not recommended)
print(vehicle._display_info()) # Accessing protected method (not recommended)
bike = Bike("Mountain Bike", 45)
print(bike.bike_info()) # Accessing protected method within subclass
Output:
Truck
Vehicle name: Truck, Speed: 80
Vehicle name: Mountain Bike, Speed: 45
3. Private Attributes and Methods
Private attributes and methods use a double underscore (`__`) prefix, making them less accessible from outside the class. This is achieved through name mangling, which prevents direct access by altering the name internally.Example of Private Attributes:
class Account:
def __init__(self, owner, balance):
self.__owner = owner # Private attribute
self.__balance = balance # Private attribute
def __display_balance(self): # Private method
return f"Account owner: {self.__owner}, Balance: ${self.__balance}"
def get_balance(self):
return self.__display_balance() # Public method to access private method
account = Account("Alice", 1000)
print(account.get_balance()) # Accessing private method through a public method
print(account._Account__owner) # Accessing private attribute with name mangling (not recommended)
Output:
Account owner: Alice, Balance: $1000
Alice
4. Getters and Setters for Controlled Access
Python allows controlled access to private attributes through getters and setters, providing indirect access while protecting the integrity of the data.Example of Getters and Setters:
class Employee:
def __init__(self, name, salary):
self.__name = name # Private attribute
self.__salary = salary # Private attribute
# Getter method for name
def get_name(self):
return self.__name
# Setter method for name
def set_name(self, name):
self.__name = name
# Getter and setter for salary with validation
def get_salary(self):
return self.__salary
def set_salary(self, salary):
if salary < 0:
raise ValueError("Salary cannot be negative")
self.__salary = salary
employee = Employee("John", 50000)
print(employee.get_name()) # Accessing name through getter
employee.set_salary(55000) # Setting new salary through setter
print(employee.get_salary())
Output:
John
55000
5. Using Property Decorators for Encapsulation
Property decorators (`@property`, `@<attribute>.setter`) allow defining getter and setter methods in a concise way. This enables direct access syntax while keeping the encapsulation benefits of getters and setters.Example Using Property Decorators:
class Product:
def __init__(self, name, price):
self.__name = name # Private attribute
self.__price = price # Private attribute
@property
def price(self): # Getter method
return self.__price
@price.setter
def price(self, value): # Setter method with validation
if value < 0:
raise ValueError("Price cannot be negative")
self.__price = value
product = Product("Laptop", 1000)
print("Price:", product.price) # Accessing price through property
product.price = 1200 # Setting price through property setter
print("Updated Price:", product.price)
Output:
Price: 1000
Updated Price: 1200
6. Encapsulation in Real-World Scenarios
Encapsulation is particularly useful in applications where data consistency and security are important, such as banking or inventory management systems.Example of Encapsulation in a Banking System:
class BankAccount:
def __init__(self, account_number, balance):
self.__account_number = account_number # Private attribute
self.__balance = balance # Private attribute
def deposit(self, amount):
if amount > 0:
self.__balance += amount
return f"${amount} deposited. New balance: ${self.__balance}"
return "Invalid deposit amount"
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
return f"${amount} withdrawn. New balance: ${self.__balance}"
return "Insufficient funds or invalid amount"
def get_balance(self):
return self.__balance # Public method to access private attribute
# Example usage
account = BankAccount("12345", 1000)
print(account.deposit(500))
print(account.withdraw(200))
print("Current Balance:", account.get_balance())
Output:
$500 deposited. New balance: $1500
$200 withdrawn. New balance: $1300
Current Balance: 1300
7. Summary
Encapsulation in Python allows us to:- Protect Data Integrity: By restricting direct access to attributes, we can maintain the consistency and integrity of data.
- Simplify Interface: Expose only necessary methods for external use, simplifying how other code interacts with the class.
- Control Modification: Using setters, we can enforce rules (e.g., validation) when modifying data.