Python Abstraction

basic
Published

October 9, 2024

Python, known for its readability and ease of use, uses the power of abstraction to manage complexity effectively. Abstraction, a fundamental principle of object-oriented programming (OOP), allows you to hide complex implementation details while exposing only essential information to the user. This simplifies interaction and makes code more maintainable and scalable. Let’s look into how abstraction works in Python.

Abstraction through Abstract Base Classes (ABCs)

In Python, the abc module provides the tools for creating abstract base classes (ABCs). ABCs define a common interface for subclasses, ensuring that they implement specific methods. These methods are declared but not implemented in the ABC itself; subclasses are required to provide their own concrete implementations.

from abc import ABC, abstractmethod

class Shape(ABC):  # Define an abstract base class
    @abstractmethod
    def area(self):
        pass

    @abstractmethod
    def perimeter(self):
        pass

class Circle(Shape): # Concrete class inheriting from Shape
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14159 * self.radius * self.radius

    def perimeter(self):
        return 2 * 3.14159 * self.radius

class Square(Shape): # Another concrete class inheriting from Shape
    def __init__(self, side):
        self.side = side

    def area(self):
        return self.side * self.side

    def perimeter(self):
        return 4 * self.side

#Example Usage
circle = Circle(5)
print(f"Circle Area: {circle.area()}")
print(f"Circle Perimeter: {circle.perimeter()}")

square = Square(4)
print(f"Square Area: {square.area()}")
print(f"Square Perimeter: {square.perimeter()}")

#Trying to instantiate the abstract class will raise an error
#shape = Shape() #This will cause an error

This example showcases how Shape acts as a blueprint. Circle and Square must implement area and perimeter to be valid subclasses. The user interacts with Circle and Square without needing to know the details of area and perimeter calculations.

Abstraction through Encapsulation

Abstraction is also achieved through encapsulation – bundling data (attributes) and methods that operate on that data within a class. This hides internal workings and allows for controlled access using methods.

class BankAccount:
    def __init__(self, account_number, balance):
        self._account_number = account_number #protected attribute
        self._balance = balance #protected attribute

    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            print(f"Deposited {amount}. New balance: {self._balance}")
        else:
            print("Invalid deposit amount.")

    def withdraw(self, amount):
        if 0 < amount <= self._balance:
            self._balance -= amount
            print(f"Withdrew {amount}. New balance: {self._balance}")
        else:
            print("Insufficient balance or invalid withdrawal amount.")

    def get_balance(self):
        return self._balance

account = BankAccount("12345", 1000)
account.deposit(500)
account.withdraw(200)
print(f"Account balance: {account.get_balance()}")

#Trying to directly access the protected attributes will work, but it is discouraged
#print(account._balance)

Here, the internal representation of the BankAccount (the actual balance and account number) is hidden. Users interact with it through the deposit, withdraw, and get_balance methods, ensuring data integrity and controlled access.

Abstraction’s Benefits

Using abstraction leads to:

  • Improved code organization: Abstraction simplifies complex systems by breaking them down into manageable components.
  • Increased code reusability: Abstract base classes define a common interface, making it easier to reuse and extend code.
  • Enhanced code maintainability: Changes to the implementation details of a class don’t necessarily affect other parts of the code that use it.
  • Reduced complexity: Users interact with simplified interfaces, hiding the underlying complexity.

Using these techniques effectively will greatly improve your Python programs.