Encapsulation (Understanding  Key Concepts)

Encapsulation (Understanding Key Concepts)

Encapsulation is one of the fundamental principles of Object-Oriented Programming (OOP). It refers to the bundling of data and methods that operate on that data into a single unit, usually a class.

Concepts of Encapsulation

  1. Public Varaibles

  2. Protected Varaibles

  3. Private Variables

Public variables

Public variables can be accessed and modified from anywhere in the code.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age   

# Creating an instance
person1 = Person("Elyon", 22)

# Accessing public variables
print(person1.name) 
print(person1.age)  

# Modifying public variables
person1.age = 23
print(person1.age)

Protected Varaibles

Protected variables are indicated with a single underscore _variable.

class Car:
    def __init__(self, brand, speed):
        self._brand = brand 
        self._speed = speed  

car = Car("Toyota", 120)
print(car._brand)  # This will be technically accessible, but should be used carefully

Private Variables

Private variables are indicated with a double underscore __variable.

class Car:
    def __init__(self, brand, speed):
        self.__brand = brand 
        self.__speed = speed 

car = Car("Toyota", 120)
# print(car.__brand)  # This will raise an AttributeError

Methods in Encapsualtion

  1. Public Methods

  2. Protected Methods

  3. Private Methods

Public Methods

Public methods can be accessed from outside the class.

class Car:
    def __init__(self, brand, speed):
        self.brand = brand
        self.speed = speed

    def display_info(self):
        return f"Car Brand: {self.brand}, Speed: {self.speed} km/h"

car = Car("Toyota", 120)
print(car.display_info())  # Public method accessible from outside

Private Methods

Private methods are declared using double underscores __method_name and cannot be accessed directly outside the class.

class Car:
    def __init__(self, brand, speed):
        self.__brand = brand
        self.__speed = speed

    def __secret_info(self):
        return "This is a private method"

car = Car("Toyota", 120)
# print(car.__secret_info())  # This will raise an AttributeError

Protected Methods

Protected methods use a single underscore _method_name and are meant to be used within the class and its subclasses.

class Car:
    def __init__(self, brand, speed):
        self._brand = brand
        self._speed = speed

    def _display_protected_info(self):
        return f"Protected method: {self._brand}, {self._speed} km/h"

car = Car("Toyota", 120)
print(car._display_protected_info())  # Can be accessed but not recommended

How we use a getter and setter

Getters and setters are used to access and modify private attributes indirectly, maintaining encapsulation.

class Car:
    def __init__(self, brand, speed):
        self.__brand = brand
        self.__speed = speed

    def get_brand(self):  # Getter method
        return self.__brand

    def set_speed(self, new_speed):  # Setter method
        if new_speed > 0:
            self.__speed = new_speed
        else:
            print("Speed must be positive")

car = Car("Toyota", 120)
print(car.get_brand())  # Accessing private variable using getter
car.set_speed(150)  # Modifying private variable using setter

Conclusions

Encapsulation is an essential concept in OOP that enhances data security and modularity in software development. By using public, protected, and private variables and methods, along with getters and setters, developers can create well-structured and maintainable code.