Skip to content

Latest commit

 

History

History
108 lines (73 loc) · 4.73 KB

Encapsulation and Abstraction.md

File metadata and controls

108 lines (73 loc) · 4.73 KB

Encapsulation and Abstraction

In this module, we will explore two important concepts: encapsulation and abstraction. We will discuss access specifiers, encapsulation through getters and setters, and abstraction using abstract classes and interfaces.

Access Specifiers: Public, Private, Protected:

Access specifiers define the visibility and accessibility of class members (attributes and methods) in Python. They help control the level of encapsulation and protect the internal state of an object.

In Python, we have three access specifiers:

  • Public: Public members are accessible from anywhere, both inside and outside the class.
  • Private: Private members are accessible only within the class. They are denoted by prefixing the attribute or method name with double underscores (__).
  • Protected: Protected members are accessible within the class and its subclasses. They are denoted by prefixing the attribute or method name with a single underscore (_).

Here's an example to illustrate access specifiers:

class Person:
    def __init__(self, name):
        self.name = name           # Public attribute
        self.__age = 25           # Private attribute
        self._gender = "Female"   # Protected attribute

    def display(self):
        print(f"Name: {self.name}")
        print(f"Age: {self.__age}")
        print(f"Gender: {self._gender}")


person = Person("Alice")
person.display()
print(person.name)       # Output: Alice
print(person._gender)    # Output: Female
print(person.__age)      # Error: 'Person' object has no attribute '__age'

In this example, we define a Person class with attributes name, __age, and _gender. The name attribute is public, the __age attribute is private, and the _gender attribute is protected.

Inside the class, we can access all the attributes. However, outside the class, we can only access the public attribute name and the protected attribute _gender. Attempting to access the private attribute __age outside the class will result in an error.

Encapsulation: Getters and Setters:

Encapsulation is the practice of hiding internal implementation details of a class and providing controlled access to class members. Getters and setters are methods used to access and modify the values of private attributes, ensuring data integrity and encapsulation.

Here's an example to demonstrate encapsulation using getters and setters:

class BankAccount:
    def __init__(self):
        self.__balance = 0  # Private attribute

    def get_balance(self):
        return self.__balance

    def deposit(self, amount):
        self.__balance += amount

    def withdraw(self, amount):
        if amount <= self.__balance:
            self.__balance -= amount
        else:
            print("Insufficient balance!")

account = BankAccount()
account.deposit(100)
print(account.get_balance())  # Output: 100

account.withdraw(50)
print(account.get_balance())  # Output: 50

In this example, we define a BankAccount class with a private attribute __balance. We provide a getter method get_balance to retrieve the balance and two other methods, deposit and withdraw, to modify the balance.

Using getters and setters, we can control access to private attributes and ensure that the data is accessed and modified appropriately.

Abstraction: Abstract Classes and Interfaces:

Abstraction is a concept that focuses on hiding complex implementation details and exposing only the essential functionalities to the user. Abstract classes and interfaces are key tools for achieving abstraction in Python.

An abstract class cannot be instantiated and serves as a blueprint for derived classes. It can contain both abstract methods (methods without implementation) and concrete methods.

Here's an example of an abstract class:

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def calculate_area(self):
        pass

class Rectangle(Shape):
    def __init__(self, length, width):
        self.length = length
        self.width = width

    def calculate_area(self):
        return self.length * self.width

rectangle = Rectangle(5, 3)
print(rectangle.calculate_area())  # Output: 15

In this example, we define an abstract class Shape using the ABC module. The calculate_area method is marked as abstract using the @abstractmethod decorator. Any class inheriting from Shape must provide an implementation for this method.

We then define a concrete class Rectangle that inherits from Shape and provides an implementation for the calculate_area method.

Interfaces, on the other hand, are a collection of method signatures. In Python, interfaces are not explicitly defined like in some other languages, but they can be simulated using abstract classes or duck typing.