What is encapsulation?

What is encapsulation?

What is Encapsulation in Python?

Encapsulation is one of the four fundamental principles of Object-Oriented Programming (OOP), alongside inheritance, polymorphism, and abstraction. It refers to the concept of bundling the data (attributes) and methods (functions) that operate on the data into a single unit called a class. Encapsulation also involves restricting access to certain components of an object, ensuring that the data is not directly accessible from outside the class, which helps protect it from unauthorized access and modification.

In Python, encapsulation is implemented using classes and access modifiers such as public, private, and protected. Encapsulation allows for greater modularity and control over the data, and it helps prevent unintended interference from external code.


Key Concepts in Encapsulation

  1. Private Attributes: These are variables that are intended to be inaccessible from outside the class. In Python, private attributes are indicated by a double underscore __ before the variable name (e.g., __attribute).

  2. Public Attributes: These are variables that can be accessed from outside the class. Public attributes don't have any underscores before them (e.g., attribute).

  3. Getter and Setter Methods: These methods allow controlled access to private attributes. Getters retrieve the value of a private attribute, while setters modify the value of a private attribute.


Why Use Encapsulation?

Encapsulation helps in:

  • Data Protection: By making certain data private, it prevents accidental or unauthorized changes from external code.
  • Code Organization: Encapsulation keeps the code clean and organized by grouping related data and methods together in a class.
  • Flexibility and Maintainability: It allows you to change the internal implementation without affecting the external code that uses the class.

Example 1: Basic Encapsulation in Python

Here is a simple example to demonstrate encapsulation in Python, where we create a class Person that has private attributes for name and age and provides getter and setter methods to access and modify them.

  
class Person:
    # Constructor to initialize the person's name and age
    def __init__(self, name, age):
        self.__name = name  # private attribute
        self.__age = age    # 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 method for age
    def get_age(self):
        return self.__age

    # Setter method for age
    def set_age(self, age):
        if age > 0:
            self.__age = age
        else:
            print("Age must be positive!")

# Example usage
person1 = Person("John", 25)

# Accessing attributes using getters
print(f"Name: {person1.get_name()}")  # Output: Name: John
print(f"Age: {person1.get_age()}")    # Output: Age: 25

# Modifying attributes using setters
person1.set_name("PythonBeeTelugu")
person1.set_age(30)

print(f"Updated Name: {person1.get_name()}")  # Output: Updated Name: PythonBeeTelugu
print(f"Updated Age: {person1.get_age()}")    # Output: Updated Age: 30
  

In this example:

  • The __name and __age attributes are private, so they cannot be directly accessed from outside the Person class.
  • We provide getter and setter methods (get_name, set_name, get_age, and set_age) to access and modify these private attributes.
  • This ensures that the attributes are accessed and modified only in a controlled manner, preventing unwanted changes.

Example 2: Encapsulation with Validation

Encapsulation can also include validation to ensure that the data being set is correct or meets certain criteria. Here's an example of using encapsulation with validation:

  
class BankAccount:
    def __init__(self, account_number, balance):
        self.__account_number = account_number  # private attribute
        self.__balance = balance  # private attribute

    # Getter method for account number
    def get_account_number(self):
        return self.__account_number

    # Getter method for balance
    def get_balance(self):
        return self.__balance

    # Setter method for balance with validation
    def set_balance(self, amount):
        if amount >= 0:
            self.__balance = amount
        else:
            print("Balance cannot be negative!")

# Example usage
account = BankAccount("123456789", 1000)

# Accessing balance using getter
print(f"Account Balance: {account.get_balance()}")  # Output: Account Balance: 1000

# Modifying balance using setter
account.set_balance(2000)
print(f"Updated Account Balance: {account.get_balance()}")  # Output: Updated Account Balance: 2000

# Trying to set a negative balance
account.set_balance(-500)  # Output: Balance cannot be negative!
  

In this example:

  • The BankAccount class has private attributes __account_number and __balance.
  • The set_balance() method includes validation to ensure that the balance cannot be negative.
  • This demonstrates how encapsulation can be used to control access to attributes and enforce data integrity.

Example 3: Encapsulation with @PythonBeeTelugu

Let's consider an example where we want to model an online store's product class. We will use encapsulation to protect the price and quantity attributes, ensuring that the price cannot be negative and that the quantity remains valid.

  
class Product:
    def __init__(self, product_name, price, quantity):
        self.__product_name = product_name  # private attribute
        self.__price = price                # private attribute
        self.__quantity = quantity          # private attribute

    # Getter method for price
    def get_price(self):
        return self.__price

    # Setter method for price with validation
    def set_price(self, price):
        if price >= 0:
            self.__price = price
        else:
            print("Price cannot be negative!")

    # Getter method for quantity
    def get_quantity(self):
        return self.__quantity

    # Setter method for quantity with validation
    def set_quantity(self, quantity):
        if quantity >= 0:
            self.__quantity = quantity
        else:
            print("Quantity cannot be negative!")

# Example usage
product1 = Product("Laptop", 1500, 10)

print(f"Product: {product1.__product_name}, Price: {product1.get_price()}, Quantity: {product1.get_quantity()}")

product1.set_price(2000)  # Valid price update
product1.set_quantity(15)  # Valid quantity update

print(f"Updated Product: {product1.__product_name}, Updated Price: {product1.get_price()}, Updated Quantity: {product1.get_quantity()}")
  

Conclusion

Encapsulation is a crucial concept in Object-Oriented Programming that helps protect and manage data by bundling it with the methods that operate on it. It improves code modularity, ensures data integrity, and allows for easier maintenance and debugging. By using private attributes and providing getter and setter methods, we can control how the data is accessed and modified. In Python, encapsulation is implemented using classes and methods, and it is an important tool for building secure and organized code.

For more Python tutorials, check out @PythonBeeTelugu on YouTube!

Comments